/*-----------------------------------------------------------------------------
    
    Copyright (C) 2005 T2-Design Corp. All rights reserved.
    
    File: prog_find.c
    
    Content: Implement program find module. It will create a buffer to save 
             the program information. When the user want to find a program, 
             it will look for in the buffer first, if missed, continue to 
             search in the database, and save the program from database to the 
             buffer.

    Rules: 
        Duplicated Service Arbitration:
        1) If "original_network_id" & "trasnport_stream_id" & "service_id" are 
           the same, then it is a duplicated service.
        2) When duplicated service found in Auto Scan, 
        2.1) If "Keep Better Signal" option is selected(get_ext_value(EXT_AS_SIGNAL_FILTER) 
          returns TRUE), then the service with better signal quality will be saved, 
          the service with worse signal quality is ignored.
        2.2) If "Skip it" option is selected(get_ext_value(EXT_AS_SIGNAL_FILTER) 
          returns FALSE), then ignore the new service, don't care the signal quality.
        3) When duplicated service found in Manual Scan, the new service will be 
           saved, and the old service will be ignored.

        Duplicated LCN Arbitration:
        1) When duplicated LCN found in Auto Scan, the service with better signal 
           quality will has the correct LCN, and the LCN of the service with worse 
           signal quality will be rearranged.
        2) When duplicated LCN found in Manual Scan, the new service has the correct 
           LCN, and the old service's LCN will be rearranged.
    
    History: 
    2005/6/13 by wing
        Created this file.
    2008/12/15 by wing
        Handle duplicated LCN case.
        Add comments about duplicated service and LCN arbitration rules.
-----------------------------------------------------------------------------*/
#include <sys_config.h>
#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#include <api/libosd/osd_lib.h>
#include "win_com.h"
#include "win_com_list.h"
#include "win_com_popup.h"
#include "string.id"
#include "osd_config.h"
#include <api/libpub/lib_as.h>
#include "key.h"
#include "copper_common/dev_handle.h"
#include <hal/hal_gpio.h>
#include "t2malloc.h"
#include <api/libosd/osd_common.h>
#ifdef POLAND_SPEC_SUPPORT


#define SUPPORT_LCN_UNIQUE //If enable the feature, please take care the move LCN feature in chan list UI, please also enable the feature in win_chan_list
#define LIST_ALL_CONFLICT

#define ComMemSet MEMSET

#define GET_VADDR(_addr)  ((UINT8 *)(((UINT32)(_addr) & 0x1fffffff) | 0x80000000))

#define DBG_ASSERT  OSD_ASSERT

INT32 set_pnode_lookup(INT32 (*pnode_lookup)(P_NODE *));

#define SUPPORT_DYNAMIC_SCAN    1 //0
#define APPEND_WEAK_SIGNAL_PROGRAM  0

#define SYS_MAX_NUM_PROGRAM MAX_PROG_NUM
#define __MM_NODE_VIEW_START_ADDR (__MM_AUTOSCAN_DB_BUFFER_ADDR+__MM_AUTOSCAN_DB_BUFFER_LEN)
#define __MM_NODE_VIEW_LEN  0x400000


#define C_OP_LOOKUP     0
#define C_OP_CHECK      1

#define C_CONFLICT_STRING_LENGTH 128

typedef const UINT16 *PCWSTR;
typedef WCHAR*          PWSTR;
typedef WCHAR*          PWCHAR;


typedef enum
{
	POPUP_MSG,
	POPUP_YESNO,
	POPUP_LIST,
}POPUP_STYLE;

typedef struct 
{
    UINT32 String;      // [option], indicating text, if 0, the default text defined in m_YesnoSetup will be used.
    UINT16 StrID;
    UINT8 bFocusID;     // [option], highlight button, if 0, the default button is "No" button
    UINT8 bDefaultID;   // [option], if bWaitTime is not zero, when wait timeout, this is the default result.
    UINT8 bWaitTime;    // [option], if 0 or 0xFF, wait until user confirms, otherwise, specifies a duration seconds.
}POPUP_YESNO_PARAM;


typedef struct  
{
    UINT16 idTitle;     // [option], title string id for the popup keyboard window
    UINT32 SelStat;     // [option, in/out], depends on bMultiSel, single selection index or multi-selection bitmap.
    INT16 nCount;       // [option], specifies the option number in pTable, it must be less than 32 for multi-selection list
    UINT8 bWaitTime; 	// 0/0xFF: wait until user chooses, otherwise, wait time in seconds
    UINT32 *pTable;     // [option], depends on pCtrl, if pCtrl is NULL, this field must be specified.
    UINT32 DefSel;      // [option], default selection if pCtrl is invalid and not multisel list.
}POPUP_LIST_PARAM;


typedef enum
{
    PF_NOT_MATCHED = 0, 
    PF_KEY_MATCHED, 
    PF_ALL_MATCHED
}PF_RESULT;


typedef enum
{
    PROG_SAME = 0,
    PROG_SAME_BUT_DIFF_TP,
    PROG_DIFF_AT_ALL,
    PROG_DIFF_ORIGINAL_NETWORK_ID,
//    PROG_DIFF_NETWORK_ID,
} PROGRAM_COMPARING_RESULT;

typedef enum
{
    UNKNOWN_NETWORK_ID,
    AUSTRIAN_NETWORK_ID,
    FRENCH_NETWORK_ID,
    ITALIAN_NETWORK_ID,
    SLOVENIA_NETWORK_ID,
    SPANISH_NETWORK_ID,
    SWISS_NETWORK_ID,
}REGION_OF_NETWORK_ID;


typedef struct
{
    UINT16 delete_from_database :1; //delete the old program from database.
    UINT16 delete               :1; //set the deleted flag for the old program.
    UINT16 successor_service    :1; //old program: it will be replaced with new program. New program: PROGRAM_UPDATE.associated_prog_id = old program id.
    UINT16 update_hidden_flag   :1; //for old program: update hidden_flag only.
    UINT16 update_service_name  :1; //for old program: update service_name only.
    UINT16 update_lcn           :1; //for old program: update LCN only.
    UINT16 rearrange_lcn        :1; //for old and new program: the LCN need to be rearranged.
    UINT16 append               :1; //new program need to append into database.
} PROGRAM_UPDATE_CONTROLLER, *PTR_PROGRAM_UPDATE_CONTROLLER;

typedef struct
{
    UINT16 associated_prog_id;  //program id that successor_service will replace to.
    PROGRAM_UPDATE_CONTROLLER   ctrl;
    P_NODE p_node;
} PROGRAM_UPDATE, *PTR_PROGRAM_UPDATE;

typedef struct
{
    UINT16 nCount;
    PROGRAM_UPDATE **program_list;
}PROGRAM_LIST, *PTR_PROGRAM_LIST;

typedef struct
{
    UINT16 nCount;
    UINT16 *tp_list;
}TP_LIST, *PTR_TP_LIST;


typedef struct _PARAM_NODE
{
    UINT16 nID;
    UINT16 nChannel:15;
    UINT16 bNewNode:1;

    UINT32 prog_number			:16;
    UINT32 ts_id			    :16;

    UINT32 LCN                  :16;
    UINT32 orig_LCN             :16;
    
    UINT32 lcn_true             : 1;
    UINT32 av_flag              : 1;
    UINT32 ca_mode              : 1;
    UINT32 post_update          : 1;
    UINT32 post_lcn_update      : 1;
    UINT32 hidden_flag          : 1;
    UINT32 user_changed_service_name    : 1;
    UINT32 user_changed_lcn     : 1;
    UINT32 deleted              : 1;
    UINT32 reserved             :23;

    UINT32 prog_id;

    PROGRAM_UPDATE_CONTROLLER   ctrl;

    UINT16 current_index;
    UINT16 tp_id;
    WCHAR szName[MAX_SERVICE_NAME_LENGTH+1];

    struct _PARAM_NODE *pNext;
}PARAM_NODE, *PPARAM_NODE;

typedef struct _PROGRAM_NODE
{
    UINT16 orig_network_id;
    PPARAM_NODE pList;
}PROGRAM_NODE, *PPROGRAM_NODE;

typedef struct _PROGRAM_FIND
{
    UINT16 nCount;
    UINT16 nPos;
    UINT16 nNextID;
    PPROGRAM_NODE *pNodeIndex;
}PROGRAM_FIND, *PPROGRAM_FIND;

typedef struct 
{
    UINT16 preference_zone_1_min;
    UINT16 preference_zone_1_max;
    UINT16 preference_zone_2_min;
    UINT16 preference_zone_2_max;
    UINT16 preference_overflow_zone_max;
    UINT16 available_preference_overflow_lcn;
    UINT16 available_main_overflow_lcn;
    UINT16 new_overflow_lcn; //for main overflow full then from 849 backwards
} LCN_ZONE, *PTR_LCN_ZONE;



#define SYS_MAX_NUM_TP  300

static BOOL PostProcessing_Init();
static void PreprocessFoundProgram(P_NODE *p_node);
PROGRAM_COMPARING_RESULT CompareProgram(const P_NODE *pProg1, const P_NODE *pProg2);
static BOOL PostProcessing_InsertNode(P_NODE *p_node);
BOOL PostProcessing_AddNormalTP(UINT16 tp_id);
UINT16 PostProcessing_GetProgIdx(P_NODE *p_node);
INT32 PostProcessing_GetProgNode(UINT16 nID, P_NODE *p_node);
INT32 PostProcessing_LookupNode(P_NODE *p_node);
BOOL PostProcessing_Save();

BOOL PromptProgramDeleted(PPARAM_NODE pParam);
UINT8 PromptResolveLcnConflict(const P_NODE *pProg1, const P_NODE *pProg2);
static PWSTR *CreateLcnConflictListBuffer(UINT8 count);
static void DestroyLcnConflictListBuffer(PWSTR *pList);
static void CreateLcnConflictString(const P_NODE *pProg, PWCHAR pBuffer, UINT32 nSize);
void SetAutoResolveLcnConflict(BOOL enable);
static void MarkDeletedService();
static void MarkUpdateAppendService();
static void PARAM_NODE_to_P_Node(P_NODE *p_node, const PPARAM_NODE pParam);

#ifdef LIST_ALL_CONFLICT
static  BOOL ConflictListIinitalize();
static void ResolveLcnConflictExt();
#endif

static BOOL m_PromptMode = TRUE;
static BOOL m_AutoResolveLcnConflict = FALSE;
static PROGRAM_LIST m_ScanningFound;
static PROGRAM_LIST m_Save;
static TP_LIST m_NormalTPList;  //TP list that SDT and NIT had been receved complete.
static REGION_OF_NETWORK_ID m_cur_region_network_id;


extern UINT8 as_stop_scan_signal;

//---------------------------- PRIVATE VARIABLES ----------------------------//
static PPROGRAM_FIND m_pFind = NULL;
static OSAL_ID m_idLock = OSAL_INVALID_ID;
static UINT16 m_OldRadioCount, m_OldTVCount;
static UINT16 m_CurRadioCount, m_CurTVCount;
//---------------------------- PRIVATE FUNCTIONS ----------------------------//


#ifndef LOG_PROG_FIND
#define DBG_PRINTF(...)  do{} while(0)//libc_printf
#define PrintProgNode(...)
#define PrintParamNode(...)
#define PrintNodeTable(...)
#define PrintScanningFound(...)
#define PrintSetting(...)
#define Print_P_Node(...)
#define Print_DB(...)
#endif

#define SUB_LIST_T_OFFSET	60	// sub list title offset
#define SUB_LIST_B_OFFSET	10	// sub list bottom offset
#define SUB_LIST_H_OFFSET 	(SUB_LIST_T_OFFSET+SUB_LIST_B_OFFSET)

static PWSTR *conflict_pList;

PRESULT comlist_lcn_conflict_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	UINT16 i,wTop;
	char str_len;
    	OBJLIST* ol;
	
	PRESULT cbRet = PROC_PASS;

    	ol = (OBJLIST*)pObj;
	
	if(event==EVN_PRE_DRAW)
	{
    	wTop = OSD_GetObjListTop(ol);
    	for(i=0;i<ol->wDep && (i+wTop)<ol->wCount;i++)
    	{
			win_comlist_set_str(i + wTop,NULL,conflict_pList[i+wTop],0 );
		}
	}
	else if(event == EVN_POST_CHANGE)
		cbRet = PROC_LEAVE;

	return cbRet;
}

UINT16 win_conflict_list_open(OSD_RECT* pRect,  UINT32 popup_param)
{
	struct OSDRect rect;
	UINT16 i,count,dep,cur_idx;
	UINT16 style;
	UINT8 mark_align,offset;
	PFN_KEY_MAP winkeymap;
	PFN_CALLBACK callback;
	UINT8 back_saved;
	POPUP_LIST_PARAM *param = popup_param;

	dep = (pRect->uHeight - SUB_LIST_H_OFFSET) / 40;

       conflict_pList = param->pTable;

	count = param->nCount;
	callback = comlist_lcn_conflict_callback;

	cur_idx = param->DefSel;
	
	OSD_SetRect2(&rect,pRect);
	offset = 30;
		
	style = LIST_VER | LIST_SCROLL | LIST_FOCUS_FIRST | LIST_PAGE_KEEP_CURITEM | LIST_FULL_PAGE;
	style |= LIST_SINGLE_SLECT;
	
	winkeymap = NULL;

	mark_align = C_ALIGN_RIGHT;
	win_comlist_reset();
	win_comlist_ext_set_title(NULL, NULL, param->idTitle);
	win_comlist_set_sizestyle(count, dep,style);
	win_comlist_set_align(10,0,C_ALIGN_LEFT | C_ALIGN_VCENTER);
	win_comlist_ext_enable_scrollbar(TRUE);
	win_comlist_set_frame(rect.uLeft,rect.uTop, rect.uWidth, rect.uHeight);

	win_comlist_ext_set_title_rect(rect.uLeft+10,rect.uTop+10, rect.uWidth-20, 40);
	win_comlist_ext_set_title_style(WSTL_TEXT_30_8BIT);

	win_comlist_set_mapcallback(NULL,winkeymap,callback);
	
	win_popup_list_set_timer(1000, CTRL_MSG_TYPE_POPUP_TIMER, param->bWaitTime);

	win_comlist_ext_set_ol_frame(rect.uLeft + 10, \
		rect.uTop + SUB_LIST_T_OFFSET, \
		rect.uWidth - 40, \
		rect.uHeight - SUB_LIST_H_OFFSET);
	win_comlist_ext_set_selmark_xaligen(mark_align,offset);
	win_comlist_ext_set_selmark(0);
	win_comlist_ext_set_item_sel(cur_idx);
	
	win_comlist_ext_set_item_cur(cur_idx);

	win_comlist_popup_ext(&back_saved);

	return win_comlist_get_selitem();
}


INT32 AP_OpenPopup(POPUP_STYLE type, UINT32 popup_param)
{
	win_popup_choice_t choice, default_choice;
	UINT8 back_saved;

	if(type == POPUP_MSG)
	{
		POPUP_YESNO_PARAM  *param = popup_param;
		win_compopup_set_frame(GET_MID_L(600),GET_MID_T(100),600,220);
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg_ext(NULL, NULL, param->StrID);
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(1000);
		win_compopup_smsg_restoreback();
		return SUCCESS;
	}
       else if(type == POPUP_YESNO)
       {
       	POPUP_YESNO_PARAM  *param = popup_param;

		if(param->bWaitTime != 0)
		{
			if(param->bDefaultID == 1)
				default_choice = WIN_POP_CHOICE_YES;  //default Yes
			else
				default_choice = WIN_POP_CHOICE_NO;  //default No
		}
		win_compopup_init(WIN_POPUP_TYPE_OKNO);
		win_compopup_set_frame(GET_MID_L(850),GET_MID_T(100),850,220);

		win_compopup_set_msg_ext(NULL, param->String, NULL);
		win_compopup_set_default_choice(default_choice);
		
		win_compopup_set_timer(1000, CTRL_MSG_TYPE_POPUP_TIMER, param->bWaitTime);	

		choice = win_compopup_open_ext(&back_saved);
	
		return choice;

       }
	else //type == POPUP_LIST
	{
		OSD_RECT Rect;
		Rect.uLeft = 150;
		Rect.uTop = 200;
		Rect.uWidth = 700;
	#ifdef LIST_ALL_CONFLICT
	       POPUP_LIST_PARAM *param = popup_param;
	       if(param->nCount <=5)
			Rect.uHeight = 40*param->nCount+80;
		else
			Rect.uHeight = 40*5+80;
	#else
		Rect.uHeight = 200;
	#endif
		choice = win_conflict_list_open(&Rect, popup_param);

		return choice;
	}
	   

}

void AP_ClosePopup()
{
	win_compopup_close();
}

static int CompareKey(UINT32 key1, UINT32 key2)
{
    if(key1 > key2)
        return 1;
    else if(key1 < key2)
        return -1;
    return 0;
}

static int CompareSignal(UINT32 q1, UINT32 q2)
{
    if(q1 < q2)
        return -1;
    else if(q1 > q2)
        return 1;
	
	return 0;
}

static PF_RESULT FindParam(PPARAM_NODE pList, P_NODE *p_node, PPARAM_NODE *ppParam, UINT8 bOpMode)
{
    PPARAM_NODE pNode = pList;
    T_NODE t_node;
    INT32 er, match_count;
    PF_RESULT result = PF_KEY_MATCHED;

    er = get_tp_by_id(p_node->tp_id, &t_node);
    DBG_ASSERT(SUCCESS == er);
    while(pNode)
    {
        if(pNode->prog_number == p_node->prog_number && pNode->ts_id == t_node.t_s_id)
        {
            if(ppParam)
                *ppParam = pNode;
            return PF_ALL_MATCHED;
        }
        pNode = pNode->pNext;
    }
    if(C_OP_LOOKUP == bOpMode)
        result = PF_NOT_MATCHED;
    return result;
}

static void InsertParam(PPROGRAM_NODE pProgram, P_NODE *p_node, UINT16 nID, UINT16 nChannel, BOOL bNewNode)
{
    PPARAM_NODE pParam, pTemp, pPrev;
    T_NODE t_node;

    pParam = (PPARAM_NODE)t2_malloc(sizeof(*pParam));
    DBG_ASSERT(pParam);
    ComMemSet(pParam, 0, sizeof(*pParam));

    get_tp_by_id(p_node->tp_id, &t_node);

    pParam->nID = nID;
    pParam->nChannel = nChannel;
    if(bNewNode)
        pParam->bNewNode = 1;
    
    pParam->orig_LCN = p_node->orig_LCN;
    pParam->user_changed_service_name = p_node->user_changed_service_name;
    pParam->user_changed_lcn = p_node->user_changed_lcn;
    pParam->deleted = p_node->deleted;
    pParam->hidden_flag = p_node->hidden_flag;

    pParam->prog_number = p_node->prog_number;
    pParam->ts_id = t_node.t_s_id;
    pParam->LCN = p_node->LCN;
    pParam->lcn_true = p_node->LCN_true;
    pParam->av_flag = p_node->av_flag;
    pParam->ca_mode = p_node->ca_mode;
    pParam->current_index = pParam->current_index;
    pParam->tp_id = p_node->tp_id;
	
    pParam->prog_id = p_node->prog_id;
	
    ComUniStrCopyCharN(pParam->szName, (WCHAR*)p_node->service_name, MAX_SERVICE_NAME_LENGTH);

    pPrev = NULL;
    pTemp = pProgram->pList;
    while(pTemp != NULL)
    {
        pPrev = pTemp;
        pTemp = pTemp->pNext;
    }
    if(NULL == pPrev)
        pProgram->pList = pParam;
    else
        pPrev->pNext = pParam;
}

static PF_RESULT FindNode(P_NODE *p_node, INT16 *pPos, PPARAM_NODE *ppParam, UINT8 bOpMode)
{
    PPROGRAM_NODE pNode;
    INT16 i = 0, min = 0, max = m_pFind->nCount, pos = 0;
    int cmp = -1;
    T_NODE t_node;
    PF_RESULT result = PF_NOT_MATCHED;

    get_tp_by_id(p_node->tp_id, &t_node);
    while(min < max)
    {
        i = (min+max)/2;
        pNode = m_pFind->pNodeIndex[i];
        cmp = CompareKey(t_node.network_id, pNode->orig_network_id);
        if(!cmp)
        {
            pos = i;
            result = FindParam(pNode->pList, p_node, ppParam, bOpMode);
            break;
        }
        else if(cmp > 0)
            pos = min = i + 1;
        else
            pos = max = i;
    }
    if(pPos)
        *pPos = pos;
    return result;
}

static PPROGRAM_NODE InsertNode(P_NODE *p_node, UINT16 nChannel, BOOL bNewNode)
{
    INT16 pos;
    int Result;
    PPROGRAM_NODE pNode;
    T_NODE t_node;

    // find inserting position
    Result = FindNode(p_node, &pos, NULL, C_OP_CHECK);
    
    //If 2 programs are PF_ALL_MATCHED, but own different tp,
    //Z-Book consider they are different programs.
    //So they shall be appended into m_pFind->pNodeIndex[pos].


    if(PF_NOT_MATCHED == Result)
    {
        // move program node for inserting node
        if(m_pFind->nCount)
        {
            INT16 i;
            for(i=m_pFind->nCount; i>pos; i--)
                m_pFind->pNodeIndex[i] = m_pFind->pNodeIndex[i-1];
        }

        // add new node.
        pNode = (PPROGRAM_NODE)t2_malloc(sizeof(*pNode));
        DBG_ASSERT(pNode);
        ComMemSet(pNode, 0, sizeof(*pNode));

        get_tp_by_id(p_node->tp_id, &t_node);
        pNode->orig_network_id = t_node.network_id;

        m_pFind->pNodeIndex[pos] = pNode;
        m_pFind->nCount++;
        DBG_ASSERT(m_pFind->nCount <= SYS_MAX_NUM_PROGRAM);
    }
    else
        pNode = m_pFind->pNodeIndex[pos];

    InsertParam(pNode, p_node, m_pFind->nNextID++, nChannel, bNewNode);
    return pNode;
}

static BOOL AddNodes()
{
    P_NODE node;
    UINT16 i, count;
    INT32 er;

    count = get_prog_num(VIEW_ALL | PROG_TVRADIO_MODE,0);
    for(i=0; i<count; i++)
    {
        er = get_prog_at(i, &node);
        if(SUCCESS != er)
            break;
        InsertNode(&node, i, FALSE);
    }
    return TRUE;
}


UINT16 get_signal_intensity(UINT16 tp_id)
{
	T_NODE tp;
	
	get_tp_by_id(tp_id, &tp);
	
	return tp.intensity;	
}

BOOL PostUpdateProgram()
{
    return PostProcessing_Save();
}

//---------------------------- PUBLIC FUNCTIONS -----------------------------//
void AP_SetProgramCount(UINT16 LastRadioCount, UINT16 LastTVCount)
{
    m_OldRadioCount = m_CurRadioCount = LastRadioCount;
    m_OldTVCount = m_CurTVCount = LastTVCount;
}


BOOL  InitNodeViewCallback()
{
	if(!AddNodes())
	{
		DBG_PRINTF("%s : Initalize Node View Fail\n", __FUNCTION__);
		return FALSE;
	}
        DBG_PRINTF("%s :  Initalize Node View Successful\n", __FUNCTION__);
	 return TRUE;
}

static void FindMaxDefaultIndex(UINT16 *video_index, UINT16 *audio_index)
{
	UINT16  ProgCnt, AudioCnt, TVCnt;
	UINT16 i;
	P_NODE p_node;
	UINT16 tmp_default_index = 0;


	ProgCnt = get_prog_num(VIEW_ALL | PROG_TVRADIO_MODE, 1);
	if(ProgCnt == 0)
	{
		*video_index = 0;
		*audio_index = 0;
		return;
	}

   	TVCnt = get_prog_num(VIEW_ALL | TV_CHAN , 1);

	if(TVCnt == 0)
		*video_index = 0;
	else	
	{
		for(i=0; i<ProgCnt ; i++)
		{
			get_prog_at(i, &p_node);
			if(p_node.av_flag != 1)
				continue;
			if(p_node.default_index > tmp_default_index)			
				tmp_default_index  = p_node.default_index;
		}

		*video_index = tmp_default_index+1;
	}

	tmp_default_index = 0;
	AudioCnt = get_prog_num(VIEW_ALL | RADIO_CHAN, 1);
	
	if(AudioCnt == 0)
		*audio_index = 0;
	else
	{
		for(i=0; i<ProgCnt ; i++)
		{
			get_prog_at(i, &p_node);
			if(p_node.av_flag != 0)
				continue;
			if(p_node.default_index > tmp_default_index)			
				tmp_default_index  = p_node.default_index;
		}
		
		*audio_index = tmp_default_index+1;
	}
}


BOOL AP_InitNodeViewExt(UINT8 view_mode)
{
    UINT8 mode, temp, pre_mode;
    UINT32 ts;
    BOOL bResult = FALSE;
    UINT16 AudioCnt=0; 
    UINT16 TVCnt=0;
    UINT16 DataCnt=0;

    if(OSAL_INVALID_ID == m_idLock)
    {
        m_idLock = osal_semaphore_create(1);
        DBG_PRINTF("%s: idLock=%d\n", __FUNCTION__, m_idLock);
    }
    DBG_PRINTF("%s: start=0x%x, len=0x%x, max=0x%x\n", __FUNCTION__, 
                __MM_NODE_VIEW_START_ADDR, __MM_NODE_VIEW_LEN, 
                sizeof(PROGRAM_FIND)+SYS_MAX_NUM_PROGRAM*(sizeof(PPROGRAM_NODE)+sizeof(PROGRAM_NODE)+sizeof(PARAM_NODE)));
    t2_malloc_init(GET_VADDR(__MM_NODE_VIEW_START_ADDR), __MM_NODE_VIEW_LEN);
    m_pFind = (PPROGRAM_FIND)t2_malloc(sizeof(*m_pFind));
    DBG_ASSERT(m_pFind);
    ComMemSet(m_pFind, 0, sizeof(*m_pFind));

    m_pFind->pNodeIndex = (PPROGRAM_NODE *)t2_malloc(SYS_MAX_NUM_PROGRAM*sizeof(PPROGRAM_NODE));
    DBG_ASSERT(m_pFind->pNodeIndex);

    mode = sys_data_get_cur_chan_mode();
	
    recreate_prog_view(VIEW_SINGLE_SAT|PROG_ALL_MODE, 1);

    DataCnt = get_prog_num(VIEW_SINGLE_SAT|PROG_DATA_MODE, 1); //for data service handle
	
   if(mode == PROG_TV_MODE)
   	TVCnt = get_prog_num(VIEW_ALL | TV_CHAN, 1);
   else
	AudioCnt = get_prog_num(VIEW_ALL |RADIO_CHAN, 1);
		
    if(view_mode)
    {
        temp = (PROG_TV_MODE == mode) ? PROG_RADIO_MODE : PROG_TV_MODE;
	 if(mode == PROG_TV_MODE)
		AudioCnt = get_prog_num(VIEW_ALL |temp, 1);
	else
		TVCnt = get_prog_num(VIEW_ALL|temp, 1);
    }
    else
    {
    		if(!AddNodes())
		       return FALSE;
    }

    if (PostProcessing_Init() == FALSE)
        return FALSE;
	
    set_pnode_lookup(PostProcessing_LookupNode);

    //FindMaxDefaultIndex(&TVCnt, &AudioCnt);
	 
    AP_SetProgramCount(AudioCnt,  TVCnt);

    //if(sys_data_get_LCN() == 0)
        SetAutoResolveLcnConflict(TRUE);  //Don't prompt user for the conflict if LCN Mode was turn Off.

    node_View_inital_registor(InitNodeViewCallback);
		
    DBG_PRINTF("====================start: %s=====================\n",__FUNCTION__);
    PrintSetting();
    DBG_PRINTF("--------------------step 1: original database---------------------\n");
    PrintNodeTable();

    return bResult;
}

BOOL AP_InitNodeView()
{
    AP_InitNodeViewExt(1);
}

void AP_FreeNodeView()
{
    if(m_pFind != NULL)
    {
        set_pnode_lookup(NULL);
        m_pFind = NULL;
    }

    m_ScanningFound.nCount = 0;
    m_ScanningFound.program_list = NULL;
    m_Save.nCount=0;
   m_Save.program_list=NULL;
    m_NormalTPList.nCount = 0;
    m_NormalTPList.tp_list = NULL;
}

//=============================================================================

//Italian local original_network_id:
//Italia: 0x217C 
//RAI:  0x13E, 0x13F,  0x1B
//Mediaset:  0x110
//Telecom Italia: 0x1D

REGION_OF_NETWORK_ID RegionOfNetworkID(UINT16 net_id, UINT16 original_network_id)
{
    if (net_id >= 0x3301 && net_id <= 0x3400)
        return AUSTRIAN_NETWORK_ID;
    else if (net_id == 0x20FA || (net_id >= 0x3301 && net_id <= 0x3400) )
        return FRENCH_NETWORK_ID;
#ifdef FUBA_SUPPORT
    else if ((net_id >= 0x3001 && net_id <= 0x3100))
 #else
     else if ( (net_id >= 0x3001 && net_id <= 0x3100) \
              ||(   original_network_id == 0x217C \
                 || original_network_id == 0x13E \
                 || original_network_id == 0x13F \
                 || original_network_id == 0x1B \
                 || original_network_id == 0x110 \
                 || original_network_id == 0x1D )\
            )
 #endif
        return ITALIAN_NETWORK_ID;
    else if (net_id >= 0x3201 && net_id <= 0x3300)
        return SLOVENIA_NETWORK_ID;
    else if (net_id >= 0x3101 && net_id <= 0x3200 )
        return SPANISH_NETWORK_ID;
    else if (net_id >= 0x3201 && net_id <= 0x3300)
        return SWISS_NETWORK_ID;
    return UNKNOWN_NETWORK_ID;
}

REGION_OF_NETWORK_ID GetRegionByNetworkID(const P_NODE *pProg)
{
    T_NODE t_node;
    get_tp_by_id(pProg->tp_id, &t_node);
    return RegionOfNetworkID(t_node.net_id, t_node.network_id);
}

UINT16* GetRegionTable()
{
        static const UINT16 country_strs2[]  =  //must the same as the country_strs2[] in the win_time.c
	{
		RS_REGION_ARG,
		RS_REGION_AUS,
		RS_REGION_BRA,
		RS_REGION_CHN,
		RS_REGION_DEN,
		RS_REGION_FIN,
		RS_REGION_FRA,
		RS_REGION_GER,
		RS_REGION_HK,
		RS_REGION_ITA,
		RS_REGION_POL,
		RS_REGION_RUS,
		RS_REGION_SIG,
		RS_REGION_SPA,
		RS_REGION_SWE,
		RS_REGION_TW,
		RS_REGION_UK,
	#ifdef PERSIAN_SUPPORT	
		RS_REGION_IRAN,
	#endif	
	};

	return country_strs2;
	
}


static BOOL PostProcessing_Init()
{
    const UINT16 *pRegion = GetRegionTable();
    UINT8 region = sys_data_get_country();
    m_cur_region_network_id = UNKNOWN_NETWORK_ID;
    if(RS_REGION_FRA == pRegion[region])
        m_cur_region_network_id = FRENCH_NETWORK_ID;
    else if(RS_REGION_ITA== pRegion[region])
        m_cur_region_network_id = ITALIAN_NETWORK_ID;
    
    else if(RS_REGION_SPA== pRegion[region])
        m_cur_region_network_id = SPANISH_NETWORK_ID;

    SetAutoResolveLcnConflict(FALSE);
    
    m_ScanningFound.nCount = 0;
    m_ScanningFound.program_list = (PROGRAM_UPDATE **)t2_malloc(SYS_MAX_NUM_PROGRAM*sizeof(PROGRAM_UPDATE*));
    DBG_ASSERT(m_ScanningFound.program_list);
    if (m_ScanningFound.program_list == NULL)
        return FALSE;
    ComMemSet((UINT8 *)m_ScanningFound.program_list, 0, sizeof(SYS_MAX_NUM_PROGRAM*sizeof(PROGRAM_UPDATE*)));

     m_Save.nCount = 0;
    m_Save.program_list = (PROGRAM_UPDATE **)t2_malloc(SYS_MAX_NUM_PROGRAM*sizeof(PROGRAM_UPDATE*));
    DBG_ASSERT(m_Save.program_list);
    if (m_Save.program_list == NULL)
        return FALSE;
    ComMemSet((UINT8 *)m_Save.program_list, 0, sizeof(SYS_MAX_NUM_PROGRAM*sizeof(PROGRAM_UPDATE*)));

#ifdef LIST_ALL_CONFLICT
   ConflictListIinitalize();
#endif

    m_NormalTPList.nCount = 0;
    m_NormalTPList.tp_list = (UINT16 *)t2_malloc(SYS_MAX_NUM_TP*sizeof(UINT16));
    DBG_ASSERT(m_NormalTPList.tp_list);
    if (m_NormalTPList.tp_list == NULL)
        return FALSE;
    ComMemSet((UINT8 *)m_NormalTPList.tp_list, 0, sizeof(SYS_MAX_NUM_TP*sizeof(UINT16)));
    return TRUE;
}

static BOOL PostProcessing_InsertNode(P_NODE *p_node)
{
    PROGRAM_UPDATE * pProg;
    if(m_ScanningFound.nCount >= SYS_MAX_NUM_PROGRAM)
        return FALSE;
    pProg = (PROGRAM_UPDATE *)t2_malloc(sizeof(PROGRAM_UPDATE));
    ComMemSet((UINT8 *)pProg, 0, sizeof(PROGRAM_UPDATE) );
    MEMCPY((UINT8 *)&pProg->p_node, (UINT8 *)p_node, sizeof(P_NODE));
    PreprocessFoundProgram(&pProg->p_node);
    m_ScanningFound.program_list[m_ScanningFound.nCount]= pProg;
    m_ScanningFound.nCount++;
    return TRUE;
}

BOOL PostProcessing_AddNormalTP(UINT16 tp_id)
{
    if(m_NormalTPList.nCount >= SYS_MAX_NUM_TP)
        return FALSE;
    m_NormalTPList.tp_list[m_NormalTPList.nCount] = tp_id;
    m_NormalTPList.nCount++;
    return TRUE;
}


UINT8*  get_def_langcode()
{
	extern char *stream_iso_639lang_abbr[];
	SYSTEM_DATA* p_sys_data=sys_data_get();
	return (UINT8*)&stream_iso_639lang_abbr[p_sys_data->lang.Audio_lang_1];
}

static UINT8 FindDefaultAudioIdx(P_NODE *p_node)
{
    INT32 i=0,j=0;
    UINT32 cur_audio=0;
    UINT8 *plangcode=NULL;
    UINT8 usr_lang_sel;

    UINT8 audio_count = p_node->audio_count;
    UINT8 *audio_type = p_node->audio_type;
    UINT16 *audio_pid = p_node->audio_pid;
    UINT8 audio_lang[P_MAX_AUDIO_NUM][3];
    
	for(i=0; i<audio_count; i++)
		get_audio_lang3b((UINT8 *)&p_node->audio_lang[i], audio_lang[i]);
    
    plangcode = get_def_langcode();

    if(audio_count > 1)
    {
        INT32 k=0; 
        UINT32 record[P_MAX_AUDIO_NUM];
        MEMSET(record, 0, P_MAX_AUDIO_NUM*4);
        UINT32 default_sel = 0xFFFFFFFF, und_sel = 0xFFFFFFFF;
      
        for(j=0; j<audio_count; j++)
        {
            if(audio_type[j] ==0x0)
            {
#ifdef DEFAULT_AUDIO_AVOID_AC3
                if(audio_pid[j] & AC3_DES_EXIST)
                    continue;
#endif
                record[k++] = (UINT32)j;
            }
        }
        if(k >0)
        {
            for(j=0;j<k;j++)
            {
                if(MEMCMP(audio_lang[record[j]], plangcode, 3)==0)
                {
                    break;
                }                      
                else if(und_sel == 0xFFFFFFFF)
                {                   
                    if( (MEMCMP(audio_lang[record[j]], "und", 3)==0)
                        || (MEMCMP(audio_lang[record[j]], "UND", 3)==0))
                    {
                        und_sel = record[j];
                    }
                    else if(default_sel == 0xFFFFFFFF)
                    {
                        default_sel = record[j]; 
                    }
                }
            }
            if(j==k)
            {
                if(und_sel!=0xFFFFFFFF)
                {
                    cur_audio = und_sel;
                }
                else if(default_sel!=0xFFFFFFFF)
                {
                    cur_audio = default_sel;
                }                
                else 
                {
                    cur_audio = record[0];
                    for(j=1;j<k;j++)//select lowest PID
                    {
                        if(audio_pid[record[j]] < audio_pid[cur_audio])
                            cur_audio = record[j];
                    }
                }
            }
            else
            {
                cur_audio = record[j];
            }
        }
        else            
        {
            cur_audio = 0;           
            for(j=1;j<audio_count;j++)//select lowest PID
            {
                if(audio_pid[j] < audio_pid[cur_audio])
                    cur_audio = j;
            }
        }
    }
    else
    {
        cur_audio = 0;
    }
    return cur_audio;
}

static void PreprocessFoundProgram(P_NODE *p_node)
{
    UINT16 i;

    p_node->cur_audio = FindDefaultAudioIdx(p_node);
}

PROGRAM_COMPARING_RESULT CompareProgram(const P_NODE *pProg1, const P_NODE *pProg2)
{
    T_NODE t_node1, t_node2;
    
    if( pProg1->av_flag != pProg2->av_flag)
        return PROG_DIFF_AT_ALL;
    
    get_tp_by_id(pProg1->tp_id, &t_node1);
    get_tp_by_id(pProg2->tp_id, &t_node2);
    if( t_node1.t_s_id != t_node2.t_s_id \
        || pProg1->prog_number != pProg2->prog_number )
        return PROG_DIFF_AT_ALL;
#ifdef CHECK_DUPLICATE_PROGRAM_NAME 
    if( ComUniStrCmp((PWSTR)(pProg1->service_name), (PWSTR)(pProg2->service_name), FALSE) != 0 )
        return PROG_DIFF_AT_ALL;
#endif
    if( t_node1.network_id != t_node2.network_id )
        return PROG_DIFF_ORIGINAL_NETWORK_ID;
 
    return PROG_SAME;
}
    
UINT16 PostProcessing_GetProgIdx(P_NODE *p_node)
{
    P_NODE *pProg = NULL;
    UINT16 nPos = INVALID_ID;

    osal_semaphore_capture(m_idLock, OSAL_WAIT_FOREVER_TIME);
    for (nPos = 0; nPos < m_ScanningFound.nCount; ++nPos)
    {
        pProg = &m_ScanningFound.program_list[nPos]->p_node;
        if ( CompareProgram(p_node, pProg) == PROG_SAME  \
             && p_node->tp_id == pProg->tp_id )
             {
             pProg->prog_id=p_node->prog_id;//add by IRIS on 8/5
             break;
             }
    }
    osal_semaphore_release(m_idLock);
    return (nPos < m_ScanningFound.nCount ? nPos : INVALID_ID);
}

UINT32 get_prog_id_indb(P_NODE *p_node)
{
    P_NODE *pProg = NULL;
    UINT16 nPos = INVALID_ID;
    UINT32 prog_index_indb=0;

    osal_semaphore_capture(m_idLock, OSAL_WAIT_FOREVER_TIME);
    for (nPos = 0; nPos < m_ScanningFound.nCount; ++nPos)
    {
        pProg = &m_ScanningFound.program_list[nPos]->p_node;
        if ( CompareProgram(p_node, pProg) == PROG_SAME  \
             && p_node->tp_id == pProg->tp_id )
           {
           prog_index_indb=pProg->prog_id;
           break;
          }
    }
  
    osal_semaphore_release(m_idLock);
    return prog_index_indb;
}
INT32 PostProcessing_GetProgNode(UINT16 nID, P_NODE *p_node)
{
    UINT16 i;
    PPARAM_NODE pParam;

    osal_semaphore_capture(m_idLock, OSAL_WAIT_FOREVER_TIME);
    ComMemSet((UINT8 *)p_node, 0, sizeof(*p_node));
    if (nID >= m_ScanningFound.nCount)
    {
        osal_semaphore_release(m_idLock);
        return !SUCCESS;
    }
    
    MEMCPY((UINT8 *)p_node, (UINT8 *)&m_ScanningFound.program_list[nID]->p_node, sizeof(P_NODE));

    osal_semaphore_release(m_idLock);
    return SUCCESS;
}

INT32 PostProcessing_LookupNode(P_NODE *p_node)
{
    BOOL result;
    //UINT8 op_mode = (add_flag == 0xFF) ? C_OP_CHECK : C_OP_LOOKUP;
    UINT8 op_mode = C_OP_LOOKUP;

    if(C_OP_LOOKUP == op_mode)
    {
        osal_semaphore_capture(m_idLock, OSAL_WAIT_FOREVER_TIME);
        result = PostProcessing_InsertNode(p_node);
        if (FALSE == result)
        {
            DBG_PRINTF("%s: full.\n", __FUNCTION__);
        }
        osal_semaphore_release(m_idLock);
    }
    
    if(C_OP_LOOKUP == op_mode)
        return SUCCESS; //step 1: make p_search.c:add_search_prog() don't append it into database.
    else
        return SUCCESS; //step 2: make p_search.c:tp_search_update() always sent out message: ASM_TYPE_DUP_PROGRAM.
    
}


BOOL PromptProgramDeleted(PPARAM_NODE pParam)
{
    BOOL confirm = TRUE;
    POPUP_YESNO_PARAM param;
    WCHAR wstr[200];
    WCHAR space[10];
    UINT8 len;
    
    if ( !m_PromptMode )
        return TRUE;
    
    AP_ClosePopup();
    
    ComUniStrCopyCharN(wstr, pParam->szName, ARRAY_SIZE(wstr)-1);
    ComAscStr2Uni("  ", space);
    len = ComUniStrCat(wstr, space);
    len += ComUniStrCopyCharN(&wstr[len], OSD_GetUnicodeString(RS_DISPLAY_SURE_TO_DELETE), ARRAY_SIZE(wstr)-1-len );
    param.String = (UINT32)wstr;
    param.bFocusID = 1;
    param.bDefaultID = 1;
    param.bWaitTime = 10;
    INT32 ret = AP_OpenPopup(POPUP_YESNO, (UINT32)&param);
    confirm = (WIN_POP_CHOICE_YES == ret);


    //param.StrID = RS_MSG_SAVING_DATA;
    //AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
    return confirm;
}

UINT8 PromptResolveLcnConflict(const P_NODE *pProg1, const P_NODE *pProg2)
{
    POPUP_LIST_PARAM ListParam = 
    {
        RS_WHICH_PROGRAM_HOLD_THE_LCN, 0, 0, 0 , NULL, 0
    };
    INT32 popup_result = SUCCESS;
    UINT8 total_option=2+1, result;
    PWSTR *pList;
    POPUP_YESNO_PARAM param;	

    if ( !m_PromptMode || m_AutoResolveLcnConflict)
        return 0;   //auto choose pProg1.

    AP_ClosePopup();

    pList = CreateLcnConflictListBuffer(total_option);
    ASSERT(pList != NULL);

    // make popup list string
    CreateLcnConflictString(pProg1, pList[0], C_CONFLICT_STRING_LENGTH);
    CreateLcnConflictString(pProg2, pList[1], C_CONFLICT_STRING_LENGTH);
    ComUniStrCopyCharN(pList[2], OSD_GetUnicodeString(RS_AUTOMATICALLY_WITH_NO_PROMPT), C_CONFLICT_STRING_LENGTH-1);

    // Indicate end-user to handle conflict items
    ListParam.pTable = (UINT32 *)pList;
    ListParam.nCount =total_option;
    ListParam.DefSel = ListParam.SelStat;
    ListParam.bWaitTime = 10;
    popup_result = AP_OpenPopup(POPUP_LIST, (UINT32)&ListParam);
//    if(popup_result != POPUP_SUCCESS)
//    {
//        SetAutoResolveLcnConflict(TRUE);
//        result = 0;  //choose pProg1.
//    }
    if( total_option >2 && popup_result == (UINT8)(total_option - 1) )
    {
        SetAutoResolveLcnConflict(TRUE);
        result = 0;  //choose pProg1.
    }
    else
        result = popup_result;;

    DestroyLcnConflictListBuffer(pList);

    //param.StrID = RS_MSG_SAVING_DATA;
    //AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
	
    return result;

}

static void ConfirmDeleteService()
{
    UINT16 i;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;
    
    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(param = pn->pList; NULL != param; param = param->pNext)
        {
            if(param->ctrl.delete_from_database)
            {
             
                if(PromptProgramDeleted(param) == FALSE)
                
                {
                    param->ctrl.delete_from_database = 0;
                }
                #if 0
                else
                {
                    er = del_prog_at(param->nChannel);
                   // DBG_ASSERT(SUCCESS == er);
                }
                #endif
            }
            else if(param->ctrl.delete)
            {
               
               if(PromptProgramDeleted(param) == FALSE)
               
                {
                    param->ctrl.delete = 0;
                }
               #if 0
                else
                {
                    er = del_prog_at(param->nChannel);
                    //DBG_ASSERT(SUCCESS == er);
                }
                #endif
            }
        }
    }
}

static PPARAM_NODE CheckLcnConflictWithOldProgram(const P_NODE *pProg, const PPARAM_NODE MySelf)
{
    UINT16 i;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam;

    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(pParam = pn->pList; NULL != pParam; pParam = pParam->pNext)
        {
            if(pParam == MySelf)
                continue;
	#ifndef SUPPORT_LCN_UNIQUE		
            if(pParam->av_flag != pProg->av_flag)
                continue;
	#endif		
            if (pParam->LCN == P_SEARCH_LCN_INVALID   \
                || pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database)
                continue;
            if (pParam->LCN == pProg->LCN)
                return pParam;
        }
    }
    return NULL;
}

static INT8 AutoResolveLcnConflictByCurrentRegion(const P_NODE *pProg1, const P_NODE *pProg2)
{
    //Z-Book: The program belongs to the current region shall hold the LCN,
    //another program belongs to the other region shall be arrange to the Main Overflow zone. 
    REGION_OF_NETWORK_ID region1, region2;
    region1 = GetRegionByNetworkID(pProg1);
    region2 = GetRegionByNetworkID(pProg2);
    if ( region1 != region2 )
    {
        if ( region1 == m_cur_region_network_id )
            return 0;   //auto choose pProg1.
        if ( region2 == m_cur_region_network_id )
            return 1;   //auto choose pProg2.
    }
    return -1;
}

static PTR_PROGRAM_UPDATE CheckLcnConflictWithNewProgram(const P_NODE *pProg, const PTR_PROGRAM_UPDATE MySelf)
{
    UINT16 idx;
    PROGRAM_UPDATE *pProgUpg;

    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);

        if(pProgUpg == MySelf)
            continue;
#ifndef SUPPORT_LCN_UNIQUE		
        if(pProgUpg->p_node.av_flag != pProg->av_flag)
            continue;
#endif		
        if (pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID   \
            || pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == pProg->LCN)
            return pProgUpg;
    }
    return NULL;
}

static void ResolveLcnConflict()
{
    INT8 Choose = -1;
    UINT16 i;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam, pConflictWithOldProgram;
    PTR_PROGRAM_UPDATE pConflictWithNewProgram;
    P_NODE Prog, Prog2;

    UINT16 idx;
    PROGRAM_UPDATE *pProgUpg;

    //check for all old programs that need to update LCN.
    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(pParam = pn->pList; NULL != pParam; pParam = pParam->pNext)
        {
            if (pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database \
                || ! pParam->ctrl.update_lcn \
               )
                continue;
            if (pParam->LCN == P_SEARCH_LCN_INVALID)
            {
                pParam->ctrl.rearrange_lcn = 1;
                pParam->ctrl.update_lcn = 1;
                continue;
            }
            
            PARAM_NODE_to_P_Node(&Prog, pParam);
            pConflictWithOldProgram = CheckLcnConflictWithOldProgram(&Prog, pParam);
            if(NULL != pConflictWithOldProgram)
            {
                PARAM_NODE_to_P_Node(&Prog2, pConflictWithOldProgram);
                Choose = AutoResolveLcnConflictByCurrentRegion(&Prog, &Prog2);
                if (Choose < 0)
                    Choose = PromptResolveLcnConflict(&Prog, &Prog2);
                else
                {
                    if(Choose == 0)
                        pConflictWithOldProgram->LCN = P_SEARCH_LCN_INVALID;
                    else
                        pParam->LCN = P_SEARCH_LCN_INVALID;
                }
                
                if(Choose == 0)
                {
                    pConflictWithOldProgram->ctrl.rearrange_lcn = 1;
                    pConflictWithOldProgram->ctrl.update_lcn = 1;
                }
                else
                {
                    pParam->ctrl.rearrange_lcn = 1;
                }
                continue;
            }

            pConflictWithNewProgram = CheckLcnConflictWithNewProgram(&Prog, NULL);
            if(NULL != pConflictWithNewProgram)
            {
                Choose = AutoResolveLcnConflictByCurrentRegion(&Prog, &pConflictWithNewProgram->p_node);
                if (Choose < 0)
                    Choose = PromptResolveLcnConflict(&Prog, &pConflictWithNewProgram->p_node);
                else
                {
                    if(Choose == 0)
                        pConflictWithNewProgram->p_node.LCN = P_SEARCH_LCN_INVALID;
                    else
                        pParam->LCN = P_SEARCH_LCN_INVALID;
                }

                if(Choose == 0)
                {
                    pConflictWithNewProgram->ctrl.rearrange_lcn = 1;
                }
                else
                {
                    pParam->ctrl.rearrange_lcn = 1;
                }
                continue;
            }
        }
    }


    //check for all new programs that need to be appended or successor program.
    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        
        if ( pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID)
        {
            pProgUpg->ctrl.rearrange_lcn = 1;
            continue;
        }
        
        pConflictWithOldProgram = CheckLcnConflictWithOldProgram(&pProgUpg->p_node, NULL);
        if(NULL != pConflictWithOldProgram)
        {
            PARAM_NODE_to_P_Node(&Prog2, pConflictWithOldProgram);
            Choose = AutoResolveLcnConflictByCurrentRegion(&Prog2, &pProgUpg->p_node);
            if (Choose < 0)
                Choose = PromptResolveLcnConflict(&Prog2, &pProgUpg->p_node);
            else
            {
                if(Choose == 0)
                    pProgUpg->p_node.LCN = P_SEARCH_LCN_INVALID;
                else
                    pConflictWithOldProgram->LCN = P_SEARCH_LCN_INVALID;
            }

            if(Choose == 0)
            {
                pProgUpg->ctrl.rearrange_lcn = 1;
            }
            else
            {
                pConflictWithOldProgram->ctrl.rearrange_lcn = 1;
                pConflictWithOldProgram->ctrl.update_lcn = 1;
            }
            continue;   //check next program.
        }

        pConflictWithNewProgram = CheckLcnConflictWithNewProgram(&pProgUpg->p_node, pProgUpg);
        if(NULL != pConflictWithNewProgram)
        {
            Choose = AutoResolveLcnConflictByCurrentRegion(&pProgUpg->p_node, &pConflictWithNewProgram->p_node);
            if (Choose < 0)
                Choose = PromptResolveLcnConflict(&pProgUpg->p_node, &pConflictWithNewProgram->p_node);
            else
            {
                if(Choose == 0)
                    pConflictWithNewProgram->p_node.LCN = P_SEARCH_LCN_INVALID;
                else
                    pProgUpg->p_node.LCN = P_SEARCH_LCN_INVALID;
            }

            if(Choose == 0)
            {
                pConflictWithNewProgram->ctrl.rearrange_lcn = 1;
            }
            else
            {
                pProgUpg->ctrl.rearrange_lcn = 1;
                pProgUpg->ctrl.update_lcn = 1;
            }
            continue;   //check next program.
        }
    }
    
}


static UINT16 find_free_lcn(UINT8 av_flag, UINT16 base)
{
    UINT16 i, idx;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam;
    PROGRAM_UPDATE *pProgUpg;
    BOOL restart;

    for(i=0; i<m_pFind->nCount; i=(restart? 0:i+1) )
    {
        restart = FALSE;
        pn = m_pFind->pNodeIndex[i];
        for(pParam=pn->pList; NULL!=pParam; pParam = pParam->pNext)
        {
            if (
		#ifndef SUPPORT_LCN_UNIQUE		
		  pParam->av_flag != av_flag ||
		 #endif
                pParam->LCN == P_SEARCH_LCN_INVALID   \
                || pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database)
                continue;
            if (pParam->LCN == base)
            {
                ++base;
                restart = TRUE;
                break;
            }
        }
    }

    for (idx = 0; idx < m_ScanningFound.nCount; idx=(restart? 0:idx+1) )
    {
        restart = FALSE;
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (  
	#ifndef SUPPORT_LCN_UNIQUE 
		pProgUpg->p_node.av_flag != av_flag ||
	#endif	
            pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID   \
            || pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == base)
        {
            ++base;
            restart = TRUE;
        }
    }
    return base;
}

static UINT16 find_new_free_lcn(UINT8 av_flag, UINT16 base)
{
    UINT16 i, idx;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam;
    PROGRAM_UPDATE *pProgUpg;
    BOOL restart;

    if(base == 0)
    	return 0;
    for(i=0; i<m_pFind->nCount; i=(restart? 0:i+1) )
    {
        restart = FALSE;
        pn = m_pFind->pNodeIndex[i];
        for(pParam=pn->pList; NULL!=pParam; pParam = pParam->pNext)
        {
            if (   
	#ifndef SUPPORT_LCN_UNIQUE 
		 pParam->av_flag != av_flag ||
	#endif		
      		  pParam->LCN == P_SEARCH_LCN_INVALID   \
                || pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database)
                continue;
            if (pParam->LCN == base)
            {
                --base;
                restart = TRUE;
                break;
            }
        }
    }

    for (idx = 0; idx < m_ScanningFound.nCount; idx=(restart? 0:idx+1) )
    {
        restart = FALSE;
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (
	#ifndef SUPPORT_LCN_UNIQUE 			
	     pProgUpg->p_node.av_flag != av_flag ||
	#endif	
            pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID   \
            || pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == base)
        {
            --base;
            restart = TRUE;
        }
    }
    return base;
}

static UINT16 rearrange_lcn_by_lcn_zone(UINT16 lcn, PTR_LCN_ZONE p_lcn_zone, UINT8 av_flag)
{
//   For Italian LCN:
//   a. LCN from 75 to 89 (Preference Overflow zone) are reserved for conflicting channels with LCN is 10~19 or 50~74. 
//      If LCN 89 had been occupied too, then assign the LCN from 850 to 999.
//   b. LCN from 850 to 999 (Main Overflow zone) are reserved for conflicting channels with 89<LCN<850 or no LCN, or LCN=0.

    UINT16 free_lcn;

#if 0

    free_lcn = find_free_lcn(av_flag, p_lcn_zone->available_main_overflow_lcn);
    p_lcn_zone->available_main_overflow_lcn = free_lcn + 1;
    
    if(p_lcn_zone->available_main_overflow_lcn>1000)
    {
    	    free_lcn = find_new_free_lcn(av_flag, p_lcn_zone->new_overflow_lcn);
    	    p_lcn_zone->new_overflow_lcn= free_lcn-1;
    }

    return free_lcn;
	
#else

    if ((lcn == 0 \
        || lcn > p_lcn_zone->preference_overflow_zone_max \
        || p_lcn_zone->available_preference_overflow_lcn > p_lcn_zone->preference_overflow_zone_max) 
        && p_lcn_zone->available_main_overflow_lcn<1000)
    {
        free_lcn = find_free_lcn(av_flag, p_lcn_zone->available_main_overflow_lcn);
        p_lcn_zone->available_main_overflow_lcn = free_lcn + 1;
	 if(free_lcn >=1000)
	 	goto OVERFLOW_FULL;
	 else
	        return free_lcn;
    }
    
    if (  (lcn >= p_lcn_zone->preference_zone_1_min && lcn <= p_lcn_zone->preference_zone_1_max) \
        ||(lcn >= p_lcn_zone->preference_zone_2_min && lcn <= p_lcn_zone->preference_zone_2_max) )
        
    {
        free_lcn = find_free_lcn(av_flag, p_lcn_zone->available_preference_overflow_lcn);
        if (free_lcn <= p_lcn_zone->preference_overflow_zone_max)
        {
            p_lcn_zone->available_preference_overflow_lcn = free_lcn + 1;
            return free_lcn;
        }
        else    //make available_preference_overflow_lcn become full.
            p_lcn_zone->available_preference_overflow_lcn = p_lcn_zone->preference_overflow_zone_max + 1;
    }

    //if available_preference_overflow_lcn is full, 
    //or the conflict lcn is not belong to the preerence zone,
    //then assign a lcn from available_main_overflow_lcn.
    free_lcn = find_free_lcn(av_flag, p_lcn_zone->available_main_overflow_lcn);
    p_lcn_zone->available_main_overflow_lcn = free_lcn + 1;


    //the main overflow occupies service numbers 850 to 999. In case Main Overflow space would get filled up, 
    //free positions from 849 backwards SHALL be used.
    if(p_lcn_zone->available_main_overflow_lcn>1000)
    {
OVERFLOW_FULL:    
    	    free_lcn = find_new_free_lcn(av_flag, p_lcn_zone->new_overflow_lcn);
    	    p_lcn_zone->new_overflow_lcn= free_lcn-1;
    }
	
    return free_lcn;
	
 #endif 
}

static void rearrange_lcn_by_region(UINT8 av_flag)
{
    const UINT16 *pRegion = GetRegionTable();
    UINT8 region = sys_data_get_country();
    UINT16 base, idx, i;
    UINT8 chan_mode, lcn_mode;
    INT32 er;
    P_NODE p_node;
    LCN_ZONE lcn_zone;

    PROGRAM_UPDATE *pProgUpg;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;

    if(RS_REGION_AUS == pRegion[region])
        base = 350;
    else if(RS_REGION_UK == pRegion[region])
        base = 800;
    else if(RS_REGION_ITA== pRegion[region])
    {
        lcn_zone.preference_zone_1_min= 10;
        lcn_zone.preference_zone_1_max= 19;
        lcn_zone.preference_zone_2_min= 50;
        lcn_zone.preference_zone_2_max= 74;
        lcn_zone.available_preference_overflow_lcn = 75;
        lcn_zone.preference_overflow_zone_max = 89;
        lcn_zone.available_main_overflow_lcn = 850;
        lcn_zone.new_overflow_lcn = 849;
        base = lcn_zone.available_main_overflow_lcn;
    }
    else
        base = 1000;

   //rearrange LCN of old programs stored in database that need to update LCN.
    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(param=pn->pList; NULL!=param; param = param->pNext)
        {
            if (   param->av_flag != av_flag \
                || ! param->ctrl.rearrange_lcn   \
                || param->deleted \
                || param->ctrl.delete  \
                || param->ctrl.successor_service \
                || param->ctrl.delete_from_database)
                continue;
            
            if (RS_REGION_ITA == pRegion[region])
            {
                	PARAM_NODE_to_P_Node(&p_node, param);
//                if ( GetRegionByNetworkID(&p_node) != m_cur_region_network_id )
//                {
//                    param->LCN = P_SEARCH_LCN_INVALID;
//                }
                param->LCN = rearrange_lcn_by_lcn_zone(param->LCN, &lcn_zone, av_flag);
            }
            else
            {
                base = find_free_lcn(av_flag, base);
                param->LCN = base;
                ++base;
            }
            param->lcn_true = 0;
            param->ctrl.update_lcn = 1;
            param->ctrl.rearrange_lcn = 0;
        }
    }

    //rearrange LCN of all new programs.
    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (   pProgUpg->p_node.av_flag != av_flag \
            || ! pProgUpg->ctrl.rearrange_lcn   \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;

        if (RS_REGION_ITA == pRegion[region])
        {
//            if ( GetRegionByNetworkID(&pProgUpg->p_node) != m_cur_region_network_id )
//            {
//                pProgUpg->p_node.LCN = P_SEARCH_LCN_INVALID;
//            }
            pProgUpg->p_node.LCN = rearrange_lcn_by_lcn_zone(pProgUpg->p_node.LCN, &lcn_zone, av_flag);
        }
        else
        {
            base = find_free_lcn(av_flag, base);
            pProgUpg->p_node.LCN = base;
            ++base;
        }
        pProgUpg->p_node.LCN_true = 0;
        pProgUpg->ctrl.rearrange_lcn = 0;
    }
}

static void rearrange_lcn_by_default(UINT8 av_flag)
{
    UINT16	base;
    UINT32  idx, i;

    PROGRAM_UPDATE *pProgUpg;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;

    base = 1;

    //rearrange LCN of old programs stored in database that need to update LCN.
    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(param=pn->pList; NULL!=param; param = param->pNext)
        {
            if (   param->av_flag != av_flag \
                || ! param->ctrl.rearrange_lcn   \
                || param->deleted \
                || param->ctrl.delete  \
                || param->ctrl.successor_service \
                || param->ctrl.delete_from_database)
                continue;
            
            base = find_free_lcn(av_flag, base);
            param->LCN = base;
            param->lcn_true = 0;
            param->ctrl.update_lcn = 1;
            param->ctrl.rearrange_lcn = 0;
            ++base;
        }
    }

    //rearrange LCN of all new programs.
    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (   pProgUpg->p_node.av_flag != av_flag \
            || ! pProgUpg->ctrl.rearrange_lcn   \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        base = find_free_lcn(av_flag, base);
        pProgUpg->p_node.LCN = base;
        pProgUpg->p_node.LCN_true = 0;
        pProgUpg->ctrl.rearrange_lcn = 0;
        ++base;
    }
}

void rearrange_lcn()
{
    if(1)
    {
        rearrange_lcn_by_region(PROG_TV_MODE);
        rearrange_lcn_by_region(PROG_RADIO_MODE);
    }
    else
    {
        rearrange_lcn_by_default(PROG_TV_MODE);
        rearrange_lcn_by_default(PROG_RADIO_MODE);
    }
}


static PWSTR *CreateLcnConflictListBuffer(UINT8 count)
{
    PWSTR *pList = NULL;
    UINT8 *pBuffer ;
    int size, i;

    size = sizeof(PWSTR)*count + sizeof(WCHAR)*C_CONFLICT_STRING_LENGTH*count;
    pBuffer = (UINT8 *)t2_malloc(size);
    if(NULL == pBuffer)
        return NULL;

    pList = (PWSTR *)pBuffer;
    for(i=0; i<count; i++)
    {
        size = sizeof(PWSTR)*count + sizeof(WCHAR)*C_CONFLICT_STRING_LENGTH*i;
        pList[i] = (PWSTR)(&pBuffer[size]);
    }

    return pList;
}

static void DestroyLcnConflictListBuffer(PWSTR *pList)
{
    if(pList != NULL)
        t2_free((PVOID)pList);
}


static void CreateLcnConflictString(const P_NODE *pProg, PWCHAR pBuffer, UINT32 nSize)
{
    UINT32 len=0;
    char buf[256];
    T_NODE t_node;

    get_tp_by_id(pProg->tp_id, &t_node);
	sprintf(buf, "LCN %d ", pProg->LCN);
    len = ComAscStr2Uni(buf, pBuffer);
    len += ComUniStrCopyCharN(&pBuffer[len], OSD_GetUnicodeString(RS_ASSIGN_TO), nSize-len);
	sprintf(buf, " %d.%03dMHz ", t_node.frq/1000, t_node.frq%1000);
    len += ComAscStr2Uni(buf, &pBuffer[len]);
    ASSERT(len < nSize);
    len += ComUniStrCopyCharN(&pBuffer[len], (PCWSTR)pProg->service_name, nSize-len);
   
}


void SetAutoResolveLcnConflict(BOOL enable)
{
    m_AutoResolveLcnConflict = enable;
}

void SetPromptMode(BOOL enable)
{
    m_PromptMode = enable;
}

static void MarkDeletedService()
{
    UINT16 i, j;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;
    P_NODE p_node;

    //Check old progams stayed at these normal TP whether still exist in the TS.
    for(j=0; j<m_NormalTPList.nCount; j++)
    {
        for(i=0; i<m_pFind->nCount; i++)
        {
            pn = m_pFind->pNodeIndex[i];
            for(param = pn->pList; param!=NULL; param = param->pNext)
            {
                if( m_NormalTPList.tp_list[j] == param->tp_id   \
                    && !param->deleted )
                {
                    PARAM_NODE_to_P_Node(&p_node, param);
                    if (PostProcessing_GetProgIdx(&p_node) == INVALID_ID)
                    {
                        param->ctrl.delete = TRUE;
                    }
                }
            }
        }
    }
}

static PROGRAM_COMPARING_RESULT PostProcessing_FindNode(P_NODE *p_node, INT16 *pPos, PPARAM_NODE *ppParam)
{
    INT16 i = 0, min = 0, max = m_pFind->nCount, pos = 0;
    int cmp = -1;
    T_NODE t_node;
    PROGRAM_COMPARING_RESULT result = PROG_DIFF_AT_ALL;
    PPROGRAM_NODE pNode;
    PPARAM_NODE pParam = NULL;

    get_tp_by_id(p_node->tp_id, &t_node);
    result = PROG_DIFF_AT_ALL;
    min = 0;
    max = m_pFind->nCount;
    cmp = -1;
    while(min < max)
    {
        i = (min+max)/2;
        pNode = m_pFind->pNodeIndex[i];
        cmp = CompareKey(t_node.network_id, pNode->orig_network_id);
        if(!cmp)
        {
            pos = i;
            for (pParam = pNode->pList; NULL != pParam; pParam = pParam->pNext)
            {
                //|| pParam->deleted 
                if ( pParam->ctrl.delete_from_database \
                    || pParam->av_flag != p_node->av_flag)
                    continue;
                if(pParam->prog_number == p_node->prog_number && pParam->ts_id == t_node.t_s_id)
                {
                    if (p_node->tp_id == pParam->tp_id)
                    {
                        result = PROG_SAME;
                        if(ppParam)
                            *ppParam = pParam;
                        break;
                    }
                    result = PROG_SAME_BUT_DIFF_TP; //it need to continue to find whether exist PROG_SAME later.
                }
            }
            break;
        }
        else if(cmp > 0)
            pos = min = i + 1;
        else
            pos = max = i;
    }
    if(pPos)
        *pPos = pos;
    return result;
}

static void MarkUpdatedAndAppendedService()
{
    UINT16 idx;
    PROGRAM_UPDATE *pProgUpg;
    PROGRAM_COMPARING_RESULT result = PROG_DIFF_AT_ALL;
    PPARAM_NODE pParam = NULL;

    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        result = PostProcessing_FindNode(&pProgUpg->p_node, NULL, &pParam);

	if ( PROG_SAME_BUT_DIFF_TP == result )
	{
            if ( pProgUpg->p_node.orig_LCN != 0 )    //do not append program that if its lcn==0.
			    pProgUpg->ctrl.append = 1;  //it will be appended into channel list.
	}
        else if(PROG_SAME == result)
        {
            ASSERT(pParam);
            if ( pParam->deleted )
            {
                if ( pProgUpg->p_node.orig_LCN == 0 )
                    pParam->ctrl.delete_from_database = 1;
                continue;  //Don't reintroduce the deleted program.
            }
            if ( pProgUpg->p_node.orig_LCN == 0 )  //(Unclaimed in Z-Book),really delete this program from database.
            {
                pParam->ctrl.delete_from_database = 1;
                continue;
            }
            
            if ( ! pParam->user_changed_service_name )  //user had never modified the name.
            {
                if (ComUniStrCmp((PWSTR)(pProgUpg->p_node.service_name), pParam->szName) != 0)
                {
                    ComUniStrCopyCharN(pParam->szName, (PWSTR)(pProgUpg->p_node.service_name),  MAX_SERVICE_NAME_LENGTH);
			        pParam->ctrl.update_service_name = 1;
                }
            }
            
//            if ( ! pParam->user_changed_lcn && pProgUpg->p_node.lcn_true )  //user had never modified the LCN, and the new LCN is real LCN.
            if ( ! pParam->user_changed_lcn )  //user had never modified the LCN.
            {
                //do not check (pParam->LCN != pProgUpg->p_node.LCN || pParam->lcn_true != pProgUpg->p_node.lcn_true )
                if ( pParam->orig_LCN != pProgUpg->p_node.orig_LCN )
                {
                    pParam->orig_LCN = pProgUpg->p_node.orig_LCN;
                    pParam->LCN = pProgUpg->p_node.LCN;
                    pParam->lcn_true = pProgUpg->p_node.LCN_true;
		      pParam->ctrl.update_lcn = 1;
                }
            }

            if ( pParam->hidden_flag != pProgUpg->p_node.hidden_flag )
            {
                	 pParam->hidden_flag = pProgUpg->p_node.hidden_flag;
		        pParam->ctrl.update_hidden_flag = 1;
            }
        }
        else    //PROG_DIFF_AT_ALL
		{
	            if ( pProgUpg->p_node.orig_LCN != 0 )    //do not append program that if its lcn==0.
	            {
				    pProgUpg->ctrl.append = 1;  //it will be appended into channel list.
	            }
		}
    }
}

static void MarkSuccessorService()
{
    UINT16 idx, i;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;
    PROGRAM_UPDATE *pProgUpg;

    T_NODE t_node1, t_node2;
    PPARAM_NODE DeletedService, DeletedServiceOfOtherNetwork, LcnConflictService;
    PPARAM_NODE Target;
    BOOL user_changed_lcn;

    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if ( ! pProgUpg->ctrl.append   \
            || ! pProgUpg->p_node.LCN_true \
            || pProgUpg->p_node.orig_LCN == P_SEARCH_LCN_INVALID \
           )
           continue;
            
        DeletedService = NULL;
        DeletedServiceOfOtherNetwork = NULL;
        LcnConflictService = NULL;
        user_changed_lcn = FALSE;

        for(i=0; i<m_pFind->nCount; i++)
        {
            pn = m_pFind->pNodeIndex[i];
            for(param = pn->pList; NULL != param; param = param->pNext)
            {
                if( pProgUpg->p_node.av_flag == param->av_flag \
                    && ! param->ctrl.delete_from_database \
                    && ! param->ctrl.successor_service \
                    && param->orig_LCN == pProgUpg->p_node.orig_LCN )
//                        ||param->LCN == pProgUpg->p_node.LCN)
                {
                    if( param->deleted || param->ctrl.delete || param->ctrl.delete_from_database )    //check successor
                    {
                        get_tp_by_id(pProgUpg->p_node.tp_id, &t_node1);
                        get_tp_by_id(param->tp_id, &t_node2);
                        if( param->orig_LCN == pProgUpg->p_node.orig_LCN \
                            && t_node2.network_id == t_node1.network_id \
                            && t_node2.net_id == t_node1.net_id )
                        {
                            if (DeletedService == NULL)
                                DeletedService = param;
                        }
                        else if( param->orig_LCN == pProgUpg->p_node.orig_LCN \
                            && t_node2.network_id == t_node1.network_id )
                        {
                            if (DeletedServiceOfOtherNetwork == NULL)
                                DeletedServiceOfOtherNetwork = param;
                        }
                        continue;
                    }
                    
                    if (LcnConflictService == NULL)
                        LcnConflictService = param;
                    if ( param->user_changed_lcn )
                        user_changed_lcn = TRUE;
                }
            }
        }

        Target = NULL;
        if (DeletedService != NULL)
            Target = DeletedService;
        else if (DeletedServiceOfOtherNetwork != NULL)
            Target = DeletedServiceOfOtherNetwork;
        
        if (Target != NULL)
        {
            		//pProgUpg->associated_prog_id = Target->nChannel;
            		pProgUpg->associated_prog_id = Target->prog_id;
			pProgUpg->ctrl.successor_service = 1;
			pProgUpg->ctrl.append = 0;
			pProgUpg->p_node.default_index = Target->current_index;
            
			Target->ctrl.successor_service = 1;
			Target->ctrl.delete = 0;
			Target->ctrl.delete_from_database = 0;
            
            if (LcnConflictService != NULL)
            {
                //If the LCN is occupied, it shall be allocated to the Main Overflow.(7.3.4.6.3)
                pProgUpg->p_node.LCN = P_SEARCH_LCN_INVALID;
                pProgUpg->p_node.LCN_true = 0;
            }
        }
        else if (LcnConflictService != NULL && user_changed_lcn)
        {
            //If the LCN was occupied by a user modified service, 
            //then new conflict service shall be allocated to the Main Overflow.
            pProgUpg->p_node.LCN = P_SEARCH_LCN_INVALID;
            pProgUpg->p_node.LCN_true = 0;
        }
    }
}

static void PARAM_NODE_to_P_Node(P_NODE *p_node, const PPARAM_NODE pParam)
{
    ASSERT(p_node);
    ASSERT(pParam);
    
    p_node->tp_id = pParam->tp_id;
    p_node->prog_number = pParam->prog_number;
    
    p_node->LCN_true = pParam->lcn_true;
    p_node->LCN = pParam->LCN;    
    p_node->orig_LCN = pParam->orig_LCN;
    
    p_node->av_flag = pParam->av_flag;
    p_node->ca_mode = pParam->ca_mode;
    p_node->default_index = pParam->current_index;

    p_node->hidden_flag = pParam->hidden_flag;
    p_node->user_changed_service_name = pParam->user_changed_service_name;
    p_node->user_changed_lcn = pParam->user_changed_lcn;
    p_node->deleted = pParam->deleted;

    p_node->prog_id = pParam->prog_id;
    
    ComUniStrCopyCharN((WCHAR*)p_node->service_name, pParam->szName, MAX_SERVICE_NAME_LENGTH);
}


static BOOL UpdateForOldProgram(UINT8 av_flag)
{
    UINT32  idx, i;
    PROGRAM_UPDATE *pProgUpg;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;
    P_NODE p_node;
    BOOL result_update = FALSE, update = FALSE;

    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(param=pn->pList; NULL!=param; param = param->pNext)
        {
            if (param->av_flag != av_flag \
                ||!(param->ctrl.delete \
                    || param->ctrl.update_hidden_flag  \
                    || param->ctrl.update_service_name \
                    || param->ctrl.update_lcn)
               )
               continue;
            
            if(SUCCESS != get_prog_at(param->nChannel, &p_node))
               continue;
            update = FALSE;
            if( param->ctrl.delete && p_node.deleted != 1)
            {
                p_node.deleted = 1;
                update = TRUE;
                //CHN_CleanUpForDeletedProgram(param->nChannel, param->av_flag, FALSE); Ming
            }
            if( param->ctrl.update_hidden_flag && p_node.hidden_flag != param->hidden_flag)
            {
                p_node.hidden_flag = param->hidden_flag;
                update = TRUE;
            }
            if( param->ctrl.update_service_name \
                && ComUniStrCmp((PWSTR)(p_node.service_name), param->szName) != 0 )
            {
                ComUniStrCopyCharN((PWSTR)(p_node.service_name), param->szName, MAX_SERVICE_NAME_LENGTH);
                update = TRUE;
            }
            if( param->ctrl.update_lcn \
                && ( p_node.LCN != param->LCN \
                   ||p_node.LCN_true != param->lcn_true \
                   ||p_node.orig_LCN != param->orig_LCN ) \
              )
            {
                p_node.LCN = param->LCN;
                p_node.LCN_true = param->lcn_true;
                p_node.orig_LCN = param->orig_LCN;
                update = TRUE;
            }

            if(update)
            {
                modify_prog(param->prog_id, &p_node);
                result_update = TRUE;
            }
        }
    }

    //Replaced the deleted old program with the new successor program.
    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (   pProgUpg->p_node.av_flag != av_flag \
            || ! pProgUpg->ctrl.successor_service  )
            continue;
        modify_prog(pProgUpg->associated_prog_id, &pProgUpg->p_node);
        result_update = TRUE;
    }
    return result_update;
}

static BOOL DeleteProgramFromDatabase(UINT8 av_flag)
{
    UINT32  idx, i;
    PROGRAM_UPDATE *pProgUpg;
    PPROGRAM_NODE pn;
    PPARAM_NODE param;
    P_NODE p_node;
    BOOL result_update = FALSE;
    INT32 er;
    
    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(param=pn->pList; NULL!=param; param = param->pNext)
        {
            if (param->av_flag != av_flag \
                || !(param->ctrl.delete_from_database||param->ctrl.delete))
               continue;
            else
           {
                er=del_prog_by_id(param->prog_id);
                DBG_ASSERT(SUCCESS == er);
                result_update = TRUE;
            }
        }
    }
    return result_update;
}

static BOOL AppendNewProgram(UINT8 av_flag)
{
   	INT32 result;
    UINT32  idx;
    PROGRAM_UPDATE *pProgUpg;
    P_NODE p_node;
    BOOL result_update = FALSE;
    POPUP_YESNO_PARAM param;
    UINT8 mode;	

    //mode  = (PROG_VIDEO_MODE == av_flag) ? PROG_VIDEO_MODE : PROG_AUDIO_MODE;
    //UINT32 total = get_prog_num(VIEW_ALL|mode,0);	
    UINT32 total = get_prog_num(VIEW_ALL | PROG_TVRADIO_MODE,0);	

    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        if (   pProgUpg->p_node.av_flag != av_flag \
            || ! pProgUpg->ctrl.append)
            continue;
        
        ++total;
        if (total >= SYS_MAX_NUM_PROGRAM)
        {
            if ( m_PromptMode )
            {
                AP_ClosePopup();
    		  param.StrID = RS_MSG_SPACE_FULL;
   		  AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
            }
            break;
        }
        
//        asearchmenu_inc_prog_count(&pProgUpg->p_node);
        if(pProgUpg->p_node.av_flag)
            pProgUpg->p_node.default_index = m_CurTVCount++;
        else
            pProgUpg->p_node.default_index = m_CurRadioCount++;

        MEMCPY((UINT8*)&p_node, (UINT8*)&pProgUpg->p_node, sizeof(P_NODE));
		result = add_node(TYPE_PROG_NODE, p_node.tp_id,&p_node);
	 if (result == STORE_SPACE_FULL)
        {
            if ( m_PromptMode )
            {
                AP_ClosePopup();
   		  param.StrID = RS_MSG_SPACE_FULL;
   		  AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
            }
            break;
	}
        result_update = TRUE;
    }
    return result_update;
}

static BOOL UpdateToDatabase()
{
    BOOL result_update = FALSE, update = FALSE;
    UINT8 av_flag, temp_av_flag;
    UINT16 nProgPos;

    DBG_PRINTF("---------------------step 3: before update to database: Old program---------------------\n");
    PrintNodeTable();
    DBG_PRINTF("---------------------step 3: before update to database: New found program---------------------\n");
    PrintScanningFound();
    DBG_PRINTF("\n");

    //update for another mode.
    av_flag = sys_data_get_cur_chan_mode();
    update = UpdateForOldProgram(av_flag);
    if (update)
           update_data();
    result_update |= update;

    update = DeleteProgramFromDatabase(av_flag);
    if (update)
           update_data();
    result_update |= update;
    
    update = AppendNewProgram(av_flag);
    if (update)
        update_data();
    result_update |= update;
   
    //update for another mode.
    temp_av_flag = (PROG_TV_MODE == av_flag) ? PROG_RADIO_MODE : PROG_TV_MODE;
    update = UpdateForOldProgram(temp_av_flag);
    if (update)
        update_data();
    result_update |= update;
    
    update = DeleteProgramFromDatabase(temp_av_flag);
    if (update)
        update_data();
    result_update |= update;
    
    update = AppendNewProgram(temp_av_flag);

    if (update)
        update_data();
    result_update |= update;
    

    if (result_update)
    {
        //CHN_Reset();
        //nProgPos = CHN_ArrangeAll(sys_data_get_cur_channel());
        //sys_data_set_cur_channel(nProgPos);
    }
    
    DBG_PRINTF("---------------------step 4: update database is finish:---------------------\n");
    Print_DB();
    DBG_PRINTF("\n");
    
    return result_update;
}

static save_program_with_better_signal()
{
    UINT16 i=0, j=0,n=0;
    PROGRAM_UPDATE *pProgUpg, *pProgUpg2,*pProgsave,*pProgsave2;
    UINT32 q1, q2,i1,i2;

    for (i = 0; i < m_ScanningFound.nCount; i++)
        {
            pProgUpg = m_ScanningFound.program_list[i];
            	
            for (j=0; j < n; j++)
            {
            	pProgUpg2 = m_Save.program_list[j];
            
                if (CompareProgram(&pProgUpg->p_node, &pProgUpg2->p_node) == PROG_SAME)
              {
		    
	            i1 = get_signal_intensity(pProgUpg->p_node.tp_id);
                i2 = get_signal_intensity(pProgUpg2->p_node.tp_id);
               
		        T_NODE tp1,tp2;
	
		        get_tp_by_id(pProgUpg->p_node.tp_id, &tp1);
		        get_tp_by_id(pProgUpg2->p_node.tp_id, &tp2);
	            //libc_printf("i1 is %d,i2 is %d,fre1 is %d,fre2 is %d\n",i1,i2,tp1.frq,tp2.frq);
                if(CompareSignal(i1, i2)> 0)
             	{
            	 m_Save.program_list[j]=m_ScanningFound.program_list[i];
            	
             	}
		        break;       
             }
	 
           }
		        if(j==n)	
		        {
			    m_Save.program_list[n]=m_ScanningFound.program_list[i];
	 		    n++;
	 		    m_Save.nCount++;
	 	        }
     }
            m_ScanningFound.nCount=m_Save.nCount;
            for(i=0;i<m_Save.nCount;i++)
            {
            MEMCPY(m_ScanningFound.program_list[i],m_Save.program_list[i],sizeof(PROGRAM_UPDATE));
            }

}

BOOL PostProcessing_Save()
{
    
    BOOL result_update = FALSE;
    POPUP_YESNO_PARAM param;	

    DBG_PRINTF("---------------------step 2: scanning found:---------------------\n");
    PrintScanningFound();

    do
    {
        
        MarkDeletedService();
        save_program_with_better_signal();

        MarkUpdatedAndAppendedService();
        MarkSuccessorService();
        ConfirmDeleteService();
#ifdef LIST_ALL_CONFLICT
	    ResolveLcnConflictExt();		
#else
        ResolveLcnConflict();
#endif
        rearrange_lcn();
        result_update = UpdateToDatabase();

        if ( m_PromptMode )
        {
            AP_ClosePopup();
        }
        SetPromptMode(TRUE);
    }while(0);
    return result_update;
}


UINT16 GetRestoredLCN(UINT32 Progid)
{
    P_NODE p_node;
    PPARAM_NODE pParam = NULL, pConflictWithOldProgram = NULL;
    PROGRAM_COMPARING_RESULT result = PROG_DIFF_AT_ALL;
    UINT16 lcn = P_SEARCH_LCN_INVALID;
    
	AP_InitNodeViewExt(0);
    do{
	    //    SetPromptMode(FALSE);
	        
	        if(SUCCESS != get_prog_by_id(Progid, &p_node))
	           break;    //error.
	        result = PostProcessing_FindNode(&p_node, NULL, &pParam);
	        ASSERT(result == PROG_SAME && pParam != NULL);

	        pConflictWithOldProgram = CheckLcnConflictWithOldProgram(&p_node, pParam);

	        if(NULL == pConflictWithOldProgram)
	        {
	            lcn = p_node.LCN;
	            break;
	        }
	        pParam->ctrl.rearrange_lcn = 1;
	        pParam->deleted = 0;

	        if(1)
	        {
	            rearrange_lcn_by_region(sys_data_get_cur_chan_mode());
	        }
	        else
	        {
	            rearrange_lcn_by_default(sys_data_get_cur_chan_mode());
	        }

	        lcn = pParam->LCN;
    }while(0);
    
    AP_FreeNodeView();
    return lcn;
}



INT32 ModifyLCN(UINT32 prog_id, UINT32 LCN)
{
    P_NODE p_node;
    INT32 er;

    er = get_prog_by_id(prog_id, &p_node);
    DBG_ASSERT(SUCCESS == er);

    p_node.LCN = LCN;
    if(p_node.LCN == p_node.orig_LCN)
        p_node.user_changed_lcn = 0; 
    else
	 p_node.user_changed_lcn = 1;              
	
    er = modify_prog(prog_id, &p_node);
    DBG_ASSERT(SUCCESS == er);

    return er;
}


INT32 ModifyDefaultIndex(UINT32 prog_id, UINT32 default_index)
{
    P_NODE p_node;
    INT32 er;

    er = get_prog_by_id(prog_id, &p_node);
    DBG_ASSERT(SUCCESS == er);

    p_node.default_index= default_index;
	
    er = modify_prog(prog_id, &p_node);
    DBG_ASSERT(SUCCESS == er);

    return er;
}


INT32 ModifyServiceName(P_NODE *p_node)
{
    INT32 er;

    p_node->user_changed_service_name = 1;              
	
    er = modify_prog(p_node->prog_id, p_node);
    DBG_ASSERT(SUCCESS == er);

    return er;
}


//====================================================================
#ifdef LIST_ALL_CONFLICT
#define MAX_CONFILIC 10

typedef struct
{
    UINT16 nCount;
    PARAM_NODE  **plist;
}PROGRAM_NEW_LIST;

static PROGRAM_LIST m_ConflicChannel;
static PROGRAM_NEW_LIST  m_ConflicChannelOld;

static  BOOL ConflictListIinitalize()
{
    m_ConflicChannel.nCount = 0;    
    m_ConflicChannel.program_list = (PROGRAM_UPDATE **)t2_malloc(MAX_CONFILIC*sizeof(PROGRAM_UPDATE*));
    DBG_ASSERT(m_ConflicChannel.program_list);
    if (m_ConflicChannel.program_list == NULL)
        return FALSE;
    ComMemSet((UINT8 *)m_ConflicChannel.program_list, 0, sizeof(MAX_CONFILIC*sizeof(PROGRAM_UPDATE*)));


    m_ConflicChannelOld.nCount = 0;
    m_ConflicChannelOld.plist = (PARAM_NODE **)t2_malloc(MAX_CONFILIC*sizeof(PARAM_NODE*));
    DBG_ASSERT(m_ConflicChannelOld.plist);
    if (m_ConflicChannelOld.plist == NULL)
        return FALSE;
    ComMemSet((UINT8 *)m_ConflicChannelOld.plist, 0, sizeof(MAX_CONFILIC*sizeof(PARAM_NODE*)));
}


static PPARAM_NODE CheckLcnConflictWithOldProgramExt(const P_NODE *pProg, const PPARAM_NODE MySelf)
{
    UINT16 i;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam;

    for(i=0; i<m_pFind->nCount; i++)
    {
        pn = m_pFind->pNodeIndex[i];
        for(pParam = pn->pList; NULL != pParam; pParam = pParam->pNext)
        {
            if(pParam == MySelf)
                continue;
	#ifndef SUPPORT_LCN_UNIQUE		
            if(pParam->av_flag != pProg->av_flag)
                continue;
	#endif		
            if (pParam->LCN == P_SEARCH_LCN_INVALID   \
                || pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database)
                continue;
            if(pParam->LCN == pProg->LCN)
              {
        		m_ConflicChannelOld.plist[m_ConflicChannelOld.nCount]=  pParam;                	
			m_ConflicChannelOld.nCount ++;
	        	if(m_ConflicChannelOld.nCount  > MAX_CONFILIC)
	        	{
	            		return m_ConflicChannelOld.plist[0];
	            	}
       	 }
        }
    }
    if(m_ConflicChannelOld.nCount>= 1)
    {
    		return m_ConflicChannelOld.plist[0];
    }	
    return NULL;
}

static INT8 AutoResolveOldProgLcnConflictByCurrentRegionExt(const P_NODE *pProg1)
{
    //Z-Book: The program belongs to the current region shall hold the LCN,
    //another program belongs to the other region shall be arrange to the Main Overflow zone. 
	P_NODE Prog;
	REGION_OF_NETWORK_ID region;
	UINT i, flag=0,count=0,backup_i;
	
	region = GetRegionByNetworkID(pProg1);
	if(region == m_cur_region_network_id)
		flag=TRUE;
	
	for(i=0; i<m_ConflicChannelOld.nCount ; i++)
	{
		PARAM_NODE_to_P_Node(&Prog, m_ConflicChannelOld.plist[i]);
	    	region = GetRegionByNetworkID(&Prog);
	    	if(region== m_cur_region_network_id)
	    	{	    		
	    		if(flag)
	    		{
	    			return -1;// not auto resolve,because two program have the same lcn in current region network id
			}
	    		backup_i = i;
	    		count++;
	    	}
	 } 
	
	if(flag) //auto resolve 
	{
		for(i=0; i<m_ConflicChannelOld.nCount ; i++)
    	   	{    	   	
    	   		m_ConflicChannelOld.plist[i]->ctrl.rearrange_lcn = 1;
    	   		m_ConflicChannelOld.plist[i]->LCN = P_SEARCH_LCN_INVALID;    	
		}
		return 0; // auto resolve

   	}	
	else
	{    
		if(count==1)
		{
			for(i=0; i<m_ConflicChannelOld.nCount ; i++)
    	   		{   	
    	   			if(i !=backup_i)
    	   			{
	    	   			m_ConflicChannelOld.plist[i]->ctrl.rearrange_lcn = 1;
	    	   			m_ConflicChannelOld.plist[i]->LCN = P_SEARCH_LCN_INVALID;  
    	   			}
    	   			else
    	   			{
    	   				m_ConflicChannelOld.plist[i]->ctrl.update_lcn = 1;	    	   			
    	   			}
	    	   	}  
			return 1; // auto resolve
		}			
		else
		{
			return -1;;// not auto resolve,because  the same lcn ch none  in current region network id
		}
	}
}


static INT8 AutoResolveLcnConflictByCurrentRegionExt(const P_NODE *pProg1)
{
	REGION_OF_NETWORK_ID region;
	UINT i, flag=0,count=0,backup_i;
    
	
	region = GetRegionByNetworkID(pProg1);
	if(region == m_cur_region_network_id)
		flag=TRUE;
	
	for(i=0; i<m_ConflicChannel.nCount ; i++)
	{
	    	region = GetRegionByNetworkID(&(m_ConflicChannel.program_list[i]->p_node));
	    	if(region== m_cur_region_network_id)
	    	{	    		
	    		if(flag)
    			{
	    			return -1;// not auto resolve,because two ch have the same lcn in current region network id
    			}
	    		backup_i = i;
	    		count++;
	    	}
	 } 
	
	if(flag) //auto resolve       only one  is region network id.
	{
		for(i=0; i<m_ConflicChannel.nCount ; i++)
    	   	{    	   	
    	   		m_ConflicChannel.program_list[i]->ctrl.rearrange_lcn = 1;
    	   		m_ConflicChannel.program_list[i]->p_node.LCN = P_SEARCH_LCN_INVALID;    	
		}
		return 0; // auto resolve

   	}	
	else
	{    
		if(count==1)
		{
			for(i=0; i<m_ConflicChannel.nCount ; i++)
    	   		{   	
    	   			if(i !=backup_i)
    	   			{
	    	   			m_ConflicChannel.program_list[i]->ctrl.rearrange_lcn = 1;
	    	   			m_ConflicChannel.program_list[i]->p_node.LCN = P_SEARCH_LCN_INVALID;  
    	   			}
    	   			else
    	   			{
    	   				m_ConflicChannel.program_list[i]->ctrl.update_lcn = 1;	    	   			
    	   			}
	    	   	}  
			if(backup_i ==0)
			{
				return 0x10;         //old programe is in current region.
			}
			else
			{
				return 0x11; // auto resolve  only one is region network id
			}
		}			
		else
		{
			return -1;// not auto resolve,because  the same lcn program none  in current region network id
		}
	}   		
 
    
}


UINT8 PromptResolveOldProgLcnConflict(const P_NODE *pProg1)
{
    POPUP_LIST_PARAM ListParam = 
    {
        RS_WHICH_PROGRAM_HOLD_THE_LCN, 0, 0, 0 , NULL, 0
    };
    INT32 popup_result = SUCCESS;
    UINT8 total_option=2+1, result;
    PWSTR *pList;
    POPUP_YESNO_PARAM param;
    P_NODE Prog;
    INT8 i=0;

    if ( !m_PromptMode || m_AutoResolveLcnConflict)
        return 0;   //auto choose pProg1.


    total_option = m_ConflicChannelOld.nCount +2;

    AP_ClosePopup();

    pList = CreateLcnConflictListBuffer(total_option);
    ASSERT(pList != NULL);

    // make popup list string
    CreateLcnConflictString(pProg1, pList[0], C_CONFLICT_STRING_LENGTH);
    for(i = 0; i<( total_option-2); i++)
    {	    	
    	 PARAM_NODE_to_P_Node(&Prog, m_ConflicChannelOld.plist[i]);
   	 CreateLcnConflictString(&Prog, pList[i+1], C_CONFLICT_STRING_LENGTH);
    }
    ComUniStrCopyCharN(pList[total_option-1], OSD_GetUnicodeString(RS_AUTOMATICALLY_WITH_NO_PROMPT), C_CONFLICT_STRING_LENGTH-1);

    // Indicate end-user to handle conflict items
    ListParam.pTable = (UINT32 *)pList;
    ListParam.nCount =total_option;
    ListParam.DefSel = ListParam.SelStat;
    ListParam.bWaitTime = 10;
    popup_result = AP_OpenPopup(POPUP_LIST, (UINT32)&ListParam);
//    if(popup_result != POPUP_SUCCESS)
//    {
//        SetAutoResolveLcnConflict(TRUE);
//        result = 0;  //choose pProg1.
//    }
    if( total_option >2 && popup_result == (UINT8)(total_option - 1) )
    {
        SetAutoResolveLcnConflict(TRUE);
        result = 0;  //choose pProg1.
    }
    else
        result = popup_result;

	if(result ==0)
	{
                for(i = 0; i<m_ConflicChannelOld.nCount; i++)
		 {		    
	   		m_ConflicChannelOld.plist[i]->LCN = P_SEARCH_LCN_INVALID;
	    	    	m_ConflicChannelOld.plist[i]->ctrl.rearrange_lcn =1;
		 }     	    	        
	}
	else
	{
	        for(i = 0; i<m_ConflicChannelOld.nCount; i++)
		 {		    
		    	 if((result -1) != i)
		    	 {
		   		m_ConflicChannelOld.plist[i]->LCN = P_SEARCH_LCN_INVALID;
		    	    	m_ConflicChannelOld.plist[i]->ctrl.rearrange_lcn =1;
			  }
			  else
		    	  {
		    	 	m_ConflicChannelOld.plist[i]->ctrl.update_lcn=1;
		    	  }
		 }   
		result = 1;	
	}

    DestroyLcnConflictListBuffer(pList);

    //param.StrID = RS_MSG_SAVING_DATA;
    //AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
	
    return result;

}


UINT8 PromptResolveLcnConflictExt(const P_NODE *pProg1, BOOL ConflictWithOld)
{
    POPUP_LIST_PARAM ListParam = 
    {
        RS_WHICH_PROGRAM_HOLD_THE_LCN, 0, 0, 0 , NULL, 0
    };
    INT32 popup_result = SUCCESS;
    UINT8 total_option=2+1, result;
    PWSTR *pList = NULL;
    POPUP_YESNO_PARAM param;
    INT8 i=0;

    if ( !m_PromptMode || m_AutoResolveLcnConflict)
    {
    	 goto AUTORESOLVE;
        //return 0;   //auto choose pProg1.
    }

    total_option = m_ConflicChannel.nCount +2;

    AP_ClosePopup();

    pList = CreateLcnConflictListBuffer(total_option);
    ASSERT(pList != NULL);

    // make popup list string
    if(ConflictWithOld == TRUE)
	   CreateLcnConflictString( &(m_ConflicChannel.program_list[0]->p_node), pList[0], C_CONFLICT_STRING_LENGTH);
    else		
	    CreateLcnConflictString(pProg1, pList[0], C_CONFLICT_STRING_LENGTH);
	
    for(i = 0; i<( total_option-2); i++)
    {	 
    	 if((ConflictWithOld == TRUE) && i==0)
		 CreateLcnConflictString(pProg1, pList[i+1], C_CONFLICT_STRING_LENGTH);
	 else	 	
	   	 CreateLcnConflictString( &(m_ConflicChannel.program_list[i]->p_node), pList[i+1], C_CONFLICT_STRING_LENGTH);
    }
    ComUniStrCopyCharN(pList[total_option-1], OSD_GetUnicodeString(RS_AUTOMATICALLY_WITH_NO_PROMPT), C_CONFLICT_STRING_LENGTH-1);

    // Indicate end-user to handle conflict items
    ListParam.pTable = (UINT32 *)pList;
    ListParam.nCount =total_option;
    ListParam.DefSel = ListParam.SelStat;
    ListParam.bWaitTime = 10;
    popup_result = AP_OpenPopup(POPUP_LIST, (UINT32)&ListParam);
//    if(popup_result != POPUP_SUCCESS)
//    {
//        SetAutoResolveLcnConflict(TRUE);
//        result = 0;  //choose pProg1.
//    }
    if( total_option >2 && popup_result == (UINT8)(total_option - 1) )
    {
        SetAutoResolveLcnConflict(TRUE);
AUTORESOLVE:		
	 if(ConflictWithOld == TRUE)
	 	 result = 1;
	 else	
	        result = 0;  //choose pProg1.
    }
    else
    {
    	 if(ConflictWithOld == TRUE)
    	 {
		 if(popup_result == 0)
		 	result = 1;
		 else if(popup_result == 1)
		 	result = 0;
		 else
		 	 result = popup_result;
    	 }
	 else	 	
	        result = popup_result;
    }


   	if(result ==0)
	{
		for(i = 0; i<m_ConflicChannel.nCount; i++)
		 {
		    	m_ConflicChannel.program_list[i]->p_node.LCN = P_SEARCH_LCN_INVALID;
		    	m_ConflicChannel.program_list[i]->ctrl.rearrange_lcn =1;		    	
		 }
	}
	else
	{
		 for(i = 0; i<m_ConflicChannel.nCount; i++)
		 {		    
		    	 if((result -1) != i)
		    	 {
		   		m_ConflicChannel.program_list[i]->p_node.LCN = P_SEARCH_LCN_INVALID;
		    	    	m_ConflicChannel.program_list[i]->ctrl.rearrange_lcn =1;
		    	}
		    	 else
		    	 {
		    	    	m_ConflicChannel.program_list[i]->ctrl.update_lcn=1;
		    	 }
		 }     	    	        
	       if(result != 1)
	       {
	       	result = 2;
	       }
	}

    DestroyLcnConflictListBuffer(pList);

    //param.StrID = RS_MSG_SAVING_DATA;
    //AP_OpenPopup(POPUP_MSG, &param); //IDW_SEARCH
	
    return result;

}


static PTR_PROGRAM_UPDATE CheckLcnConflictWithNewProgramExt(const P_NODE *pProg, const PTR_PROGRAM_UPDATE MySelf)
{
    UINT16 idx;
    PROGRAM_UPDATE *pProgUpg;

    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {
        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);

        if(pProgUpg == MySelf)
            continue;
#ifndef SUPPORT_LCN_UNIQUE		
        if(pProgUpg->p_node.av_flag != pProg->av_flag)
            continue;
#endif		
        if (pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID   \
            || pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == pProg->LCN)
        {
        	if(pProgUpg->p_node.hidden_flag)
        	{
        		pProgUpg->p_node.LCN  = P_SEARCH_LCN_INVALID;
        		pProgUpg->ctrl.rearrange_lcn = 1;
        		continue;
        	}
        	m_ConflicChannel.program_list[m_ConflicChannel.nCount] =  m_ScanningFound.program_list[idx];
		m_ConflicChannel.nCount ++;
        	if(m_ConflicChannel.nCount  > MAX_CONFILIC)
	            	return m_ConflicChannel.program_list[0];
        }
    }
	
    if(m_ConflicChannel.nCount>= 1)
    		return m_ConflicChannel.program_list[0];
    else
   	 return NULL;
}

static void ResolveLcnConflictExt()
{
    INT8 Choose = -1;
    UINT16 i;
    PPROGRAM_NODE pn;
    PPARAM_NODE pParam, pConflictWithOldProgram;
    PTR_PROGRAM_UPDATE pConflictWithNewProgram;
    P_NODE Prog, Prog2;

    UINT16 idx;
    PROGRAM_UPDATE *pProgUpg, *pProgOld;
    BOOL bFlag= FALSE;
    BOOL ConflictWithOld = FALSE;

    //check for all old programs that need to update LCN.
     /********************************set test condition****************************************/
    /********************************set test condition****************************************/

    //check for all old programs that need to update LCN.
    for(i=0; i<m_pFind->nCount; i++)
    {

        ComMemSet((UINT8 *)m_ConflicChannelOld.plist, 0, sizeof(MAX_CONFILIC*sizeof(PARAM_NODE*)));
        m_ConflicChannelOld.nCount = 0;
        bFlag = FALSE;
			
        pn = m_pFind->pNodeIndex[i];
        for(pParam = pn->pList; NULL != pParam; pParam = pParam->pNext)
        {
            if (pParam->deleted \
                || pParam->ctrl.delete  \
                || pParam->ctrl.successor_service \
                || pParam->ctrl.rearrange_lcn   \
                || pParam->ctrl.delete_from_database \
                || ! pParam->ctrl.update_lcn \
               )
                continue;
            if (pParam->LCN == P_SEARCH_LCN_INVALID)
            {
                pParam->ctrl.rearrange_lcn = 1;
                pParam->ctrl.update_lcn = 1;
                continue;
            }
            
            PARAM_NODE_to_P_Node(&Prog, pParam);
            pConflictWithOldProgram = CheckLcnConflictWithOldProgramExt(&Prog, pParam);
            if(NULL != pConflictWithOldProgram)
            {

		   if(pParam->hidden_flag) 
       	   {
        		 pParam->ctrl.rearrange_lcn = 1;
		        pParam->LCN = P_SEARCH_LCN_INVALID;
        		continue;
       	    }
		 
      		 for(i=0; i<m_ConflicChannelOld.nCount ; i++)
      		{
      		    	 if(m_ConflicChannelOld.plist[i]->hidden_flag)
      		    	 {		    	 	
      		    	   	m_ConflicChannelOld.plist[i]->LCN = P_SEARCH_LCN_INVALID;
      		    		m_ConflicChannelOld.plist[i]->ctrl.rearrange_lcn =1;		
      		    	 	m_ConflicChannelOld.nCount --;		    
      		    	 	bFlag = TRUE;
      		    	 }		    	 
      		    	 if(bFlag&&(i+1<m_ConflicChannelOld.nCount))
      		    	 {		    	 
      		    	 	m_ConflicChannelOld.plist[i] =m_ConflicChannelOld.plist[i+1];
      		    	 }		    	 
      		 }
		 if(m_ConflicChannelOld.nCount ==0)
		 	continue;
			
                Choose = AutoResolveOldProgLcnConflictByCurrentRegionExt(&Prog);
	        if(Choose<0)
                {
		        Choose =PromptResolveOldProgLcnConflict(&Prog);		        	
                }
                
		  if(Choose ==0)
                {
		       pParam->ctrl.update_lcn  = 1;
                }
                else // select one of the m_ConflicChannelOld list 
                {
                     pParam->ctrl.rearrange_lcn = 1;
                     pParam->LCN = P_SEARCH_LCN_INVALID;
                }
                continue;
            }            
        }
    }


    //check for all new programs that need to be appended or successor program.
    for (idx = 0; idx < m_ScanningFound.nCount; ++idx)
    {

	 ComMemSet((UINT8 *)m_ConflicChannel.program_list, 0, sizeof(MAX_CONFILIC*sizeof(PROGRAM_UPDATE*)));
        m_ConflicChannel.nCount =0;
        ComMemSet((UINT8 *)m_ConflicChannelOld.plist, 0, sizeof(MAX_CONFILIC*sizeof(PARAM_NODE*)));
        m_ConflicChannelOld.nCount = 0;

        pProgUpg = m_ScanningFound.program_list[idx];
        ASSERT(pProgUpg);
        
        if ( pProgUpg->ctrl.rearrange_lcn \
            || !(pProgUpg->ctrl.successor_service || pProgUpg->ctrl.append) \
           )
            continue;
        if (pProgUpg->p_node.LCN == P_SEARCH_LCN_INVALID)
        {
            pProgUpg->ctrl.rearrange_lcn = 1;
            continue;
        }

	ConflictWithOld = FALSE;	
        pConflictWithOldProgram = CheckLcnConflictWithOldProgramExt(&pProgUpg->p_node, NULL);
        if(NULL != pConflictWithOldProgram)
        {
            PARAM_NODE_to_P_Node(&Prog2, pConflictWithOldProgram);
      	 	pProgOld = (PROGRAM_UPDATE *)t2_malloc(sizeof(PROGRAM_UPDATE));
    		ComMemSet((UINT8 *)pProgOld, 0, sizeof(PROGRAM_UPDATE) );
    		MEMCPY((UINT8 *)&pProgOld->p_node, (UINT8 *)&Prog2, sizeof(P_NODE));    
        	m_ConflicChannel.program_list[0]=pProgOld;
        	m_ConflicChannel.program_list[0]->associated_prog_id = 0xff;
        	m_ConflicChannel.nCount =1;
		ConflictWithOld = TRUE;	
        }

        pConflictWithNewProgram = CheckLcnConflictWithNewProgramExt(&pProgUpg->p_node, pProgUpg);
        if(NULL != pConflictWithNewProgram)
        {
		for(i=0; i<m_ConflicChannel.nCount ; i++)
		{
		    	 if(m_ConflicChannel.program_list[i]->p_node.hidden_flag)
		    	 {
		    	 	if((i==0)&&(pConflictWithOldProgram!=NULL))
		    	 	{
		    	 		pConflictWithOldProgram ->ctrl.rearrange_lcn = 1;
                			pConflictWithOldProgram ->LCN = P_SEARCH_LCN_INVALID;
					if(pProgOld != NULL)
						t2_free((PVOID)pProgOld);
					ConflictWithOld = FALSE;
		    	 	}
		    	 	else
		    	 	{
			    		m_ConflicChannel.program_list[i]->ctrl.rearrange_lcn = 1;	    	   		
		    	   		m_ConflicChannel.program_list[i]->p_node.LCN = P_SEARCH_LCN_INVALID;    	
	    	   		}
		    	 	m_ConflicChannel.nCount --;		    
		    	 	bFlag = TRUE;
		    	 }		    	 
		    	 if(bFlag&&(i+1<m_ConflicChannel.nCount))
		    	 {		    	 
		    	 	m_ConflicChannel.program_list[i] =m_ConflicChannel.program_list[i+1];
		    	 }		    	 
		 }
		 if(m_ConflicChannel.nCount ==0)
		 	continue;
		
            Choose = AutoResolveLcnConflictByCurrentRegionExt(&pProgUpg->p_node);
            if (Choose < 0)
            {
                Choose = PromptResolveLcnConflictExt(&pProgUpg->p_node, ConflictWithOld);          
            }

            if(Choose == 0)
            {
                pProgUpg->ctrl.update_lcn = 1;
                if(NULL != pConflictWithOldProgram)
                {
                	pConflictWithOldProgram ->ctrl.rearrange_lcn = 1;
                	pConflictWithOldProgram ->LCN = P_SEARCH_LCN_INVALID;
                }
            }
            else if(Choose == 0x10)
            {
		  pProgUpg->ctrl.rearrange_lcn = 1;
                pProgUpg->p_node.LCN= P_SEARCH_LCN_INVALID;            	
            }
            else if(Choose == 0x11)
            {
			   pProgUpg->ctrl.rearrange_lcn = 1;
              	   pProgUpg->p_node.LCN= P_SEARCH_LCN_INVALID;   	  
              	   if(NULL != pConflictWithOldProgram)
            	  	  {
            	  		pConflictWithOldProgram ->ctrl.rearrange_lcn = 1;
                		pConflictWithOldProgram ->LCN = P_SEARCH_LCN_INVALID;
				if(pProgOld != NULL)
					t2_free((PVOID)pProgOld);		
            	 	  }
            }
            else
            {
            	  if((Choose !=1)&&(NULL != pConflictWithOldProgram))
            	  {
            	  	pConflictWithOldProgram ->ctrl.rearrange_lcn = 1;
                	pConflictWithOldProgram ->LCN = P_SEARCH_LCN_INVALID;
			if(pProgOld != NULL)
				t2_free((PVOID)pProgOld);
            	  }
                pProgUpg->ctrl.rearrange_lcn = 1;
                pProgUpg->p_node.LCN= P_SEARCH_LCN_INVALID;
            }
            continue;   //check next program.
        }
    }
    
}
#endif

#endif
